From e1fcbf9fbb0df914cdc38c379a0f34deaf270295 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 12 May 2020 16:46:17 +0800 Subject: [PATCH 01/59] Add a storage layer for attachments --- cmd/migrate_storage.go | 68 + go.mod | 2 + go.sum | 9 + integrations/attachment_test.go | 5 +- main.go | 1 + models/admin.go | 13 + models/attachment.go | 66 +- models/issue.go | 3 +- models/migrations/v96.go | 11 +- models/repo.go | 7 +- modules/migrations/gitea.go | 15 +- modules/storage/local.go | 62 + modules/storage/minio.go | 59 + modules/storage/storage.go | 42 + routers/init.go | 4 + routers/repo/attachment.go | 4 +- services/release/release.go | 4 +- vendor/github.com/go-ini/ini/.gitignore | 6 + vendor/github.com/go-ini/ini/LICENSE | 191 + vendor/github.com/go-ini/ini/Makefile | 15 + vendor/github.com/go-ini/ini/README.md | 43 + vendor/github.com/go-ini/ini/codecov.yml | 9 + vendor/github.com/go-ini/ini/data_source.go | 76 + vendor/github.com/go-ini/ini/deprecated.go | 25 + vendor/github.com/go-ini/ini/error.go | 34 + vendor/github.com/go-ini/ini/file.go | 509 + vendor/github.com/go-ini/ini/helper.go | 24 + vendor/github.com/go-ini/ini/ini.go | 168 + vendor/github.com/go-ini/ini/key.go | 829 ++ vendor/github.com/go-ini/ini/parser.go | 535 + vendor/github.com/go-ini/ini/section.go | 256 + vendor/github.com/go-ini/ini/struct.go | 724 ++ vendor/github.com/minio/minio-go/.gitignore | 3 + vendor/github.com/minio/minio-go/.travis.yml | 28 + .../github.com/minio/minio-go/CONTRIBUTING.md | 23 + vendor/github.com/minio/minio-go/LICENSE | 202 + .../github.com/minio/minio-go/MAINTAINERS.md | 35 + vendor/github.com/minio/minio-go/Makefile | 15 + vendor/github.com/minio/minio-go/NOTICE | 2 + vendor/github.com/minio/minio-go/README.md | 239 + .../github.com/minio/minio-go/README_zh_CN.md | 245 + .../minio/minio-go/api-compose-object.go | 565 + .../minio/minio-go/api-datatypes.go | 84 + .../minio/minio-go/api-error-response.go | 282 + .../minio/minio-go/api-get-lifecycle.go | 77 + .../minio/minio-go/api-get-object-acl.go | 136 + .../minio/minio-go/api-get-object-context.go | 26 + .../minio/minio-go/api-get-object-file.go | 125 + .../minio/minio-go/api-get-object.go | 659 + .../minio/minio-go/api-get-options.go | 128 + .../minio/minio-go/api-get-policy.go | 78 + vendor/github.com/minio/minio-go/api-list.go | 715 ++ .../minio/minio-go/api-notification.go | 228 + .../minio/minio-go/api-presigned.go | 215 + .../minio/minio-go/api-put-bucket.go | 306 + .../minio/minio-go/api-put-object-common.go | 111 + .../minio/minio-go/api-put-object-context.go | 33 + .../minio/minio-go/api-put-object-copy.go | 83 + .../minio-go/api-put-object-file-context.go | 64 + .../minio/minio-go/api-put-object-file.go | 27 + .../minio-go/api-put-object-multipart.go | 372 + .../minio-go/api-put-object-streaming.go | 417 + .../minio/minio-go/api-put-object.go | 267 + .../github.com/minio/minio-go/api-remove.go | 303 + .../minio/minio-go/api-s3-datatypes.go | 245 + .../github.com/minio/minio-go/api-select.go | 532 + vendor/github.com/minio/minio-go/api-stat.go | 185 + vendor/github.com/minio/minio-go/api.go | 898 ++ vendor/github.com/minio/minio-go/appveyor.yml | 39 + .../github.com/minio/minio-go/bucket-cache.go | 221 + .../minio/minio-go/bucket-notification.go | 273 + vendor/github.com/minio/minio-go/constants.go | 62 + vendor/github.com/minio/minio-go/core.go | 153 + .../github.com/minio/minio-go/hook-reader.go | 71 + .../minio/minio-go/pkg/credentials/chain.go | 89 + .../pkg/credentials/config.json.sample | 17 + .../minio-go/pkg/credentials/credentials.go | 175 + .../pkg/credentials/credentials.sample | 12 + .../minio/minio-go/pkg/credentials/doc.go | 62 + .../minio/minio-go/pkg/credentials/env_aws.go | 71 + .../minio-go/pkg/credentials/env_minio.go | 62 + .../pkg/credentials/file_aws_credentials.go | 120 + .../pkg/credentials/file_minio_client.go | 133 + .../minio/minio-go/pkg/credentials/iam_aws.go | 250 + .../pkg/credentials/signature-type.go | 77 + .../minio/minio-go/pkg/credentials/static.go | 67 + .../pkg/credentials/sts_client_grants.go | 173 + .../pkg/credentials/sts_web_identity.go | 169 + .../minio/minio-go/pkg/encrypt/server-side.go | 195 + .../s3signer/request-signature-streaming.go | 306 + .../pkg/s3signer/request-signature-v2.go | 316 + .../pkg/s3signer/request-signature-v4.go | 315 + .../minio/minio-go/pkg/s3signer/utils.go | 49 + .../minio/minio-go/pkg/s3utils/utils.go | 331 + .../minio/minio-go/pkg/set/stringset.go | 197 + .../github.com/minio/minio-go/post-policy.go | 270 + .../minio/minio-go/retry-continous.go | 69 + vendor/github.com/minio/minio-go/retry.go | 153 + .../github.com/minio/minio-go/s3-endpoints.go | 52 + vendor/github.com/minio/minio-go/s3-error.go | 61 + vendor/github.com/minio/minio-go/transport.go | 50 + vendor/github.com/minio/minio-go/utils.go | 272 + vendor/golang.org/x/net/http/httpguts/guts.go | 50 + .../golang.org/x/net/http/httpguts/httplex.go | 346 + vendor/golang.org/x/net/publicsuffix/list.go | 181 + vendor/golang.org/x/net/publicsuffix/table.go | 10046 ++++++++++++++++ vendor/modules.txt | 13 + 107 files changed, 27278 insertions(+), 62 deletions(-) create mode 100644 cmd/migrate_storage.go create mode 100644 modules/storage/local.go create mode 100644 modules/storage/minio.go create mode 100644 modules/storage/storage.go create mode 100644 vendor/github.com/go-ini/ini/.gitignore create mode 100644 vendor/github.com/go-ini/ini/LICENSE create mode 100644 vendor/github.com/go-ini/ini/Makefile create mode 100644 vendor/github.com/go-ini/ini/README.md create mode 100644 vendor/github.com/go-ini/ini/codecov.yml create mode 100644 vendor/github.com/go-ini/ini/data_source.go create mode 100644 vendor/github.com/go-ini/ini/deprecated.go create mode 100644 vendor/github.com/go-ini/ini/error.go create mode 100644 vendor/github.com/go-ini/ini/file.go create mode 100644 vendor/github.com/go-ini/ini/helper.go create mode 100644 vendor/github.com/go-ini/ini/ini.go create mode 100644 vendor/github.com/go-ini/ini/key.go create mode 100644 vendor/github.com/go-ini/ini/parser.go create mode 100644 vendor/github.com/go-ini/ini/section.go create mode 100644 vendor/github.com/go-ini/ini/struct.go create mode 100644 vendor/github.com/minio/minio-go/.gitignore create mode 100644 vendor/github.com/minio/minio-go/.travis.yml create mode 100644 vendor/github.com/minio/minio-go/CONTRIBUTING.md create mode 100644 vendor/github.com/minio/minio-go/LICENSE create mode 100644 vendor/github.com/minio/minio-go/MAINTAINERS.md create mode 100644 vendor/github.com/minio/minio-go/Makefile create mode 100644 vendor/github.com/minio/minio-go/NOTICE create mode 100644 vendor/github.com/minio/minio-go/README.md create mode 100644 vendor/github.com/minio/minio-go/README_zh_CN.md create mode 100644 vendor/github.com/minio/minio-go/api-compose-object.go create mode 100644 vendor/github.com/minio/minio-go/api-datatypes.go create mode 100644 vendor/github.com/minio/minio-go/api-error-response.go create mode 100644 vendor/github.com/minio/minio-go/api-get-lifecycle.go create mode 100644 vendor/github.com/minio/minio-go/api-get-object-acl.go create mode 100644 vendor/github.com/minio/minio-go/api-get-object-context.go create mode 100644 vendor/github.com/minio/minio-go/api-get-object-file.go create mode 100644 vendor/github.com/minio/minio-go/api-get-object.go create mode 100644 vendor/github.com/minio/minio-go/api-get-options.go create mode 100644 vendor/github.com/minio/minio-go/api-get-policy.go create mode 100644 vendor/github.com/minio/minio-go/api-list.go create mode 100644 vendor/github.com/minio/minio-go/api-notification.go create mode 100644 vendor/github.com/minio/minio-go/api-presigned.go create mode 100644 vendor/github.com/minio/minio-go/api-put-bucket.go create mode 100644 vendor/github.com/minio/minio-go/api-put-object-common.go create mode 100644 vendor/github.com/minio/minio-go/api-put-object-context.go create mode 100644 vendor/github.com/minio/minio-go/api-put-object-copy.go create mode 100644 vendor/github.com/minio/minio-go/api-put-object-file-context.go create mode 100644 vendor/github.com/minio/minio-go/api-put-object-file.go create mode 100644 vendor/github.com/minio/minio-go/api-put-object-multipart.go create mode 100644 vendor/github.com/minio/minio-go/api-put-object-streaming.go create mode 100644 vendor/github.com/minio/minio-go/api-put-object.go create mode 100644 vendor/github.com/minio/minio-go/api-remove.go create mode 100644 vendor/github.com/minio/minio-go/api-s3-datatypes.go create mode 100644 vendor/github.com/minio/minio-go/api-select.go create mode 100644 vendor/github.com/minio/minio-go/api-stat.go create mode 100644 vendor/github.com/minio/minio-go/api.go create mode 100644 vendor/github.com/minio/minio-go/appveyor.yml create mode 100644 vendor/github.com/minio/minio-go/bucket-cache.go create mode 100644 vendor/github.com/minio/minio-go/bucket-notification.go create mode 100644 vendor/github.com/minio/minio-go/constants.go create mode 100644 vendor/github.com/minio/minio-go/core.go create mode 100644 vendor/github.com/minio/minio-go/hook-reader.go create mode 100644 vendor/github.com/minio/minio-go/pkg/credentials/chain.go create mode 100644 vendor/github.com/minio/minio-go/pkg/credentials/config.json.sample create mode 100644 vendor/github.com/minio/minio-go/pkg/credentials/credentials.go create mode 100644 vendor/github.com/minio/minio-go/pkg/credentials/credentials.sample create mode 100644 vendor/github.com/minio/minio-go/pkg/credentials/doc.go create mode 100644 vendor/github.com/minio/minio-go/pkg/credentials/env_aws.go create mode 100644 vendor/github.com/minio/minio-go/pkg/credentials/env_minio.go create mode 100644 vendor/github.com/minio/minio-go/pkg/credentials/file_aws_credentials.go create mode 100644 vendor/github.com/minio/minio-go/pkg/credentials/file_minio_client.go create mode 100644 vendor/github.com/minio/minio-go/pkg/credentials/iam_aws.go create mode 100644 vendor/github.com/minio/minio-go/pkg/credentials/signature-type.go create mode 100644 vendor/github.com/minio/minio-go/pkg/credentials/static.go create mode 100644 vendor/github.com/minio/minio-go/pkg/credentials/sts_client_grants.go create mode 100644 vendor/github.com/minio/minio-go/pkg/credentials/sts_web_identity.go create mode 100644 vendor/github.com/minio/minio-go/pkg/encrypt/server-side.go create mode 100644 vendor/github.com/minio/minio-go/pkg/s3signer/request-signature-streaming.go create mode 100644 vendor/github.com/minio/minio-go/pkg/s3signer/request-signature-v2.go create mode 100644 vendor/github.com/minio/minio-go/pkg/s3signer/request-signature-v4.go create mode 100644 vendor/github.com/minio/minio-go/pkg/s3signer/utils.go create mode 100644 vendor/github.com/minio/minio-go/pkg/s3utils/utils.go create mode 100644 vendor/github.com/minio/minio-go/pkg/set/stringset.go create mode 100644 vendor/github.com/minio/minio-go/post-policy.go create mode 100644 vendor/github.com/minio/minio-go/retry-continous.go create mode 100644 vendor/github.com/minio/minio-go/retry.go create mode 100644 vendor/github.com/minio/minio-go/s3-endpoints.go create mode 100644 vendor/github.com/minio/minio-go/s3-error.go create mode 100644 vendor/github.com/minio/minio-go/transport.go create mode 100644 vendor/github.com/minio/minio-go/utils.go create mode 100644 vendor/golang.org/x/net/http/httpguts/guts.go create mode 100644 vendor/golang.org/x/net/http/httpguts/httplex.go create mode 100644 vendor/golang.org/x/net/publicsuffix/list.go create mode 100644 vendor/golang.org/x/net/publicsuffix/table.go diff --git a/cmd/migrate_storage.go b/cmd/migrate_storage.go new file mode 100644 index 0000000000000..35c1b45052fe6 --- /dev/null +++ b/cmd/migrate_storage.go @@ -0,0 +1,68 @@ +// Copyright 2018 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package cmd + +import ( + "context" + + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/models/migrations" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/storage" + + "github.com/urfave/cli" +) + +// CmdMigrateStorage represents the available migrate storage sub-command. +var CmdMigrateStorage = cli.Command{ + Name: "migrate-storage", + Usage: "Migrate the storage", + Description: "This is a command for migrating storage.", + Action: runMigrateStorage, +} + +func migrateAttachments(dstStorage storage.ObjectStorage) error { + return models.IterateAttachment(func(attach *models.Attachment) error { + _, err := storage.Copy(dstStorage, attach.UUID, storage.Attachments, attach.RelativePath()) + return err + }) +} + +func runMigrateStorage(ctx *cli.Context) error { + if err := initDB(); err != nil { + return err + } + + log.Trace("AppPath: %s", setting.AppPath) + log.Trace("AppWorkPath: %s", setting.AppWorkPath) + log.Trace("Custom path: %s", setting.CustomPath) + log.Trace("Log path: %s", setting.LogRootPath) + setting.InitDBConfig() + + if err := models.NewEngine(context.Background(), migrations.Migrate); err != nil { + log.Fatal("Failed to initialize ORM engine: %v", err) + return err + } + + tp := ctx.String("type") + + // TODO: init setting + + if err := storage.Init(); err != nil { + return err + } + + switch tp { + case "attachments": + dstStorage, err := storage.NewLocalStorage(ctx.String("dst")) + if err != nil { + return err + } + return migrateAttachments(dstStorage) + } + + return nil +} diff --git a/go.mod b/go.mod index f8b8358360914..6308dafc05067 100644 --- a/go.mod +++ b/go.mod @@ -41,6 +41,7 @@ require ( github.com/go-enry/go-enry/v2 v2.5.2 github.com/go-git/go-billy/v5 v5.0.0 github.com/go-git/go-git/v5 v5.1.0 + github.com/go-ini/ini v1.56.0 // indirect github.com/go-openapi/jsonreference v0.19.3 // indirect github.com/go-redis/redis v6.15.2+incompatible github.com/go-sql-driver/mysql v1.5.0 @@ -74,6 +75,7 @@ require ( github.com/mgechev/revive v1.0.2 github.com/mholt/archiver/v3 v3.3.0 github.com/microcosm-cc/bluemonday v1.0.3-0.20191119130333-0a75d7616912 + github.com/minio/minio-go v6.0.14+incompatible github.com/mitchellh/go-homedir v1.1.0 github.com/msteinert/pam v0.0.0-20151204160544-02ccfbfaf0cc github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5 diff --git a/go.sum b/go.sum index 4828517f068ee..0571df29bcf42 100644 --- a/go.sum +++ b/go.sum @@ -235,8 +235,15 @@ github.com/go-git/go-billy/v5 v5.0.0 h1:7NQHvd9FVid8VL4qVUMm8XifBK+2xCoZ2lSk0agR github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= github.com/go-git/go-git-fixtures/v4 v4.0.1 h1:q+IFMfLx200Q3scvt2hN79JsEzy4AmBTp/pqnefH+Bc= github.com/go-git/go-git-fixtures/v4 v4.0.1/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw= +<<<<<<< HEAD github.com/go-git/go-git/v5 v5.1.0 h1:HxJn9g/E7eYvKW3Fm7Jt4ee8LXfPOm/H1cdDu8vEssk= github.com/go-git/go-git/v5 v5.1.0/go.mod h1:ZKfuPUoY1ZqIG4QG9BDBh3G4gLM5zvPuSJAozQrZuyM= +======= +github.com/go-git/go-git/v5 v5.0.0 h1:k5RWPm4iJwYtfWoxIJy4wJX9ON7ihPeZZYC1fLYDnpg= +github.com/go-git/go-git/v5 v5.0.0/go.mod h1:oYD8y9kWsGINPFJoLdaScGCN6dlKg23blmClfZwtUVA= +github.com/go-ini/ini v1.56.0 h1:6HjxSjqdmgnujDPhlzR4a44lxK3w03WPN8te0SoUSeM= +github.com/go-ini/ini v1.56.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= +>>>>>>> Add a storage layer for attachments github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= @@ -574,6 +581,8 @@ github.com/mholt/archiver/v3 v3.3.0 h1:vWjhY8SQp5yzM9P6OJ/eZEkmi3UAbRrxCq48MxjAz github.com/mholt/archiver/v3 v3.3.0/go.mod h1:YnQtqsp+94Rwd0D/rk5cnLrxusUBUXg+08Ebtr1Mqao= github.com/microcosm-cc/bluemonday v1.0.3-0.20191119130333-0a75d7616912 h1:hJde9rA24hlTcAYSwJoXpDUyGtfKQ/jsofw+WaDqGrI= github.com/microcosm-cc/bluemonday v1.0.3-0.20191119130333-0a75d7616912/go.mod h1:8iwZnFn2CDDNZ0r6UXhF4xawGvzaqzCRa1n3/lO3W2w= +github.com/minio/minio-go v6.0.14+incompatible h1:fnV+GD28LeqdN6vT2XdGKW8Qe/IfjJDswNVuni6km9o= +github.com/minio/minio-go v6.0.14+incompatible/go.mod h1:7guKYtitv8dktvNUGrhzmNlA5wrAABTQXCoesZdFQO8= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= diff --git a/integrations/attachment_test.go b/integrations/attachment_test.go index 7fd3aa3bf3ee5..eda6fbdb57146 100644 --- a/integrations/attachment_test.go +++ b/integrations/attachment_test.go @@ -123,10 +123,7 @@ func TestGetAttachment(t *testing.T) { t.Run(tc.name, func(t *testing.T) { //Write empty file to be available for response if tc.createFile { - localPath := models.AttachmentLocalPath(tc.uuid) - err := os.MkdirAll(path.Dir(localPath), os.ModePerm) - assert.NoError(t, err) - err = ioutil.WriteFile(localPath, []byte("hello world"), 0644) + err = SaveAttachment(tc.uuid, strings.NewReader("hello world")) assert.NoError(t, err) } //Actual test diff --git a/main.go b/main.go index 90feaa9bb0e3b..74e6911bb6632 100644 --- a/main.go +++ b/main.go @@ -68,6 +68,7 @@ arguments - which can alternatively be run by running the subcommand web.` cmd.CmdDoctor, cmd.CmdManager, cmd.Cmdembedded, + cmd.CmdMigrateStorage, } // Now adjust these commands to add our global configuration options diff --git a/models/admin.go b/models/admin.go index ebd01419a8768..fbb6852581b8e 100644 --- a/models/admin.go +++ b/models/admin.go @@ -8,6 +8,7 @@ import ( "fmt" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/storage" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" @@ -65,6 +66,18 @@ func RemoveAllWithNotice(title, path string) { removeAllWithNotice(x, title, path) } +// RemoveStorageWithNotice removes a file from the storage and +// creates a system notice when error occurs. +func RemoveStorageWithNotice(bucket storage.ObjectStorage, title, path string) { + if err := bucket.Delete(path); err != nil { + desc := fmt.Sprintf("%s [%s]: %v", title, path, err) + log.Warn(title+" [%s]: %v", path, err) + if err = createNotice(x, NoticeRepository, desc); err != nil { + log.Error("CreateRepositoryNotice: %v", err) + } + } +} + func removeAllWithNotice(e Engine, title, path string) { if err := util.RemoveAll(path); err != nil { desc := fmt.Sprintf("%s [%s]: %v", title, path, err) diff --git a/models/attachment.go b/models/attachment.go index 6215de95b58b2..3ec4219641fef 100644 --- a/models/attachment.go +++ b/models/attachment.go @@ -5,15 +5,15 @@ package models import ( + "bytes" "fmt" "io" - "os" "path" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/storage" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/timeutil" - "code.gitea.io/gitea/modules/util" gouuid "github.com/google/uuid" "xorm.io/xorm" @@ -56,22 +56,16 @@ func (a *Attachment) APIFormat() *api.Attachment { } } -// AttachmentLocalPath returns where attachment is stored in local file -// system based on given UUID. -func AttachmentLocalPath(uuid string) string { - return path.Join(setting.AttachmentPath, uuid[0:1], uuid[1:2], uuid) -} - -// LocalPath returns where attachment is stored in local file system. -func (a *Attachment) LocalPath() string { - return AttachmentLocalPath(a.UUID) -} - // DownloadURL returns the download url of the attached file func (a *Attachment) DownloadURL() string { return fmt.Sprintf("%sattachments/%s", setting.AppURL, a.UUID) } +// RelativePath returns the relative path of the attachment +func (a *Attachment) RelativePath() string { + return path.Join(a.UUID[0:1], a.UUID[1:2], a.UUID) +} + // LinkedRepository returns the linked repo if any func (a *Attachment) LinkedRepository() (*Repository, UnitType, error) { if a.IssueID != 0 { @@ -100,29 +94,11 @@ func (a *Attachment) LinkedRepository() (*Repository, UnitType, error) { func NewAttachment(attach *Attachment, buf []byte, file io.Reader) (_ *Attachment, err error) { attach.UUID = gouuid.New().String() - localPath := attach.LocalPath() - if err = os.MkdirAll(path.Dir(localPath), os.ModePerm); err != nil { - return nil, fmt.Errorf("MkdirAll: %v", err) - } - - fw, err := os.Create(localPath) + size, err := storage.Attachments.Save(attach.RelativePath(), io.MultiReader(bytes.NewReader(buf), file)) if err != nil { return nil, fmt.Errorf("Create: %v", err) } - defer fw.Close() - - if _, err = fw.Write(buf); err != nil { - return nil, fmt.Errorf("Write: %v", err) - } else if _, err = io.Copy(fw, file); err != nil { - return nil, fmt.Errorf("Copy: %v", err) - } - - // Update file size - var fi os.FileInfo - if fi, err = fw.Stat(); err != nil { - return nil, fmt.Errorf("file size: %v", err) - } - attach.Size = fi.Size() + attach.Size = size if _, err := x.Insert(attach); err != nil { return nil, err @@ -238,7 +214,7 @@ func DeleteAttachments(attachments []*Attachment, remove bool) (int, error) { if remove { for i, a := range attachments { - if err := util.Remove(a.LocalPath()); err != nil { + if storage.Attachments.Delete(a.RelativePath()); err != nil { return i, err } } @@ -290,3 +266,25 @@ func DeleteAttachmentsByRelease(releaseID int64) error { _, err := x.Where("release_id = ?", releaseID).Delete(&Attachment{}) return err } + +// IterateAttachment iterates attachments +func IterateAttachment(f func(attach *Attachment) error) error { + var start int + const batchSize = 100 + for { + var attachments = make([]*Attachment, 0, batchSize) + if err := x.Limit(batchSize, start).Find(&attachments); err != nil { + return err + } + if len(attachments) == 0 { + return nil + } + start += len(attachments) + + for _, attach := range attachments { + if err := f(attach); err != nil { + return err + } + } + } +} diff --git a/models/issue.go b/models/issue.go index 07d7fc99569bc..2912f7e8ef8e2 100644 --- a/models/issue.go +++ b/models/issue.go @@ -1983,8 +1983,9 @@ func deleteIssuesByRepoID(sess Engine, repoID int64) (attachmentPaths []string, Find(&attachments); err != nil { return } + for j := range attachments { - attachmentPaths = append(attachmentPaths, attachments[j].LocalPath()) + attachmentPaths = append(attachmentPaths, attachments[j].RelativePath()) } if _, err = sess.In("issue_id", deleteCond). diff --git a/models/migrations/v96.go b/models/migrations/v96.go index 5decb832cda22..fe22e8da8ef44 100644 --- a/models/migrations/v96.go +++ b/models/migrations/v96.go @@ -13,8 +13,11 @@ import ( "xorm.io/xorm" ) -func deleteOrphanedAttachments(x *xorm.Engine) error { +func relativePath(uuid string) string { + return path.Join(uuid[0:1], uuid[1:2], uuid) +} +func deleteOrphanedAttachments(x *xorm.Engine) error { type Attachment struct { ID int64 `xorm:"pk autoincr"` UUID string `xorm:"uuid UNIQUE"` @@ -53,8 +56,10 @@ func deleteOrphanedAttachments(x *xorm.Engine) error { for _, attachment := range attachements { ids = append(ids, attachment.ID) } - if _, err := sess.In("id", ids).Delete(new(Attachment)); err != nil { - return err + if len(ids) > 0 { + if _, err := sess.In("id", ids).Delete(new(Attachment)); err != nil { + return err + } } for _, attachment := range attachements { diff --git a/models/repo.go b/models/repo.go index 146868d876426..b9296e7b75ec8 100644 --- a/models/repo.go +++ b/models/repo.go @@ -32,6 +32,7 @@ import ( "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/options" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/storage" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" @@ -1595,7 +1596,7 @@ func DeleteRepository(doer *User, uid, repoID int64) error { } releaseAttachments := make([]string, 0, len(attachments)) for i := 0; i < len(attachments); i++ { - releaseAttachments = append(releaseAttachments, attachments[i].LocalPath()) + releaseAttachments = append(releaseAttachments, attachments[i].UUID) } if _, err = sess.Exec("UPDATE `user` SET num_stars=num_stars-1 WHERE id IN (SELECT `uid` FROM `star` WHERE repo_id = ?)", repo.ID); err != nil { @@ -1720,12 +1721,12 @@ func DeleteRepository(doer *User, uid, repoID int64) error { // Remove issue attachment files. for i := range attachmentPaths { - removeAllWithNotice(x, "Delete issue attachment", attachmentPaths[i]) + RemoveStorageWithNotice(storage.Attachments, "Delete issue attachment", attachmentPaths[i]) } // Remove release attachment files. for i := range releaseAttachments { - removeAllWithNotice(x, "Delete release attachment", releaseAttachments[i]) + RemoveStorageWithNotice(storage.Attachments, "Delete release attachment", releaseAttachments[i]) } if len(repo.Avatar) > 0 { diff --git a/modules/migrations/gitea.go b/modules/migrations/gitea.go index 7d446fb408f74..8c097e143cb07 100644 --- a/modules/migrations/gitea.go +++ b/modules/migrations/gitea.go @@ -13,7 +13,6 @@ import ( "net/http" "net/url" "os" - "path" "path/filepath" "strings" "sync" @@ -26,6 +25,7 @@ import ( "code.gitea.io/gitea/modules/repository" repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/storage" "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/timeutil" @@ -275,18 +275,7 @@ func (g *GiteaLocalUploader) CreateReleases(releases ...*base.Release) error { } defer resp.Body.Close() - localPath := attach.LocalPath() - if err = os.MkdirAll(path.Dir(localPath), os.ModePerm); err != nil { - return fmt.Errorf("MkdirAll: %v", err) - } - - fw, err := os.Create(localPath) - if err != nil { - return fmt.Errorf("Create: %v", err) - } - defer fw.Close() - - _, err = io.Copy(fw, resp.Body) + _, err = storage.Attachments.Save(attach.RelativePath(), resp.Body) return err }() if err != nil { diff --git a/modules/storage/local.go b/modules/storage/local.go new file mode 100644 index 0000000000000..86f2bb58913c6 --- /dev/null +++ b/modules/storage/local.go @@ -0,0 +1,62 @@ +package storage + +import ( + "io" + "os" + "path/filepath" +) + +var ( + _ ObjectStorage = &LocalStorage{} +) + +// LocalStorage represents a local files storage +type LocalStorage struct { + dir string +} + +// NewLocalStorage returns a local files +func NewLocalStorage(bucket string) (*LocalStorage, error) { + if err := os.MkdirAll(bucket, os.ModePerm); err != nil { + return nil, err + } + + return &LocalStorage{ + dir: bucket, + }, nil +} + +// Open open a file +func (l *LocalStorage) Open(path string) (io.ReadCloser, error) { + f, err := os.Open(filepath.Join(l.dir, path)) + if err != nil { + return nil, err + } + return f, nil +} + +// Save save a file +func (l *LocalStorage) Save(path string, r io.Reader) (int64, error) { + p := filepath.Join(l.dir, path) + if err := os.MkdirAll(filepath.Dir(p), os.ModePerm); err != nil { + return 0, err + } + + // always override + if err := os.RemoveAll(p); err != nil { + return 0, err + } + + f, err := os.Create(p) + if err != nil { + return 0, err + } + defer f.Close() + return io.Copy(f, r) +} + +// Delete delete a file +func (l *LocalStorage) Delete(path string) error { + p := filepath.Join(l.dir, path) + return os.Remove(p) +} diff --git a/modules/storage/minio.go b/modules/storage/minio.go new file mode 100644 index 0000000000000..57f8d8a6b7b58 --- /dev/null +++ b/modules/storage/minio.go @@ -0,0 +1,59 @@ +package storage + +import ( + "io" + "strings" + + "github.com/minio/minio-go" +) + +var ( + _ ObjectStorage = &MinioStorage{} +) + +// MinioStorage returns a minio bucket storage +type MinioStorage struct { + client *minio.Client + location string + bucket string + basePath string +} + +// NewMinioStorage returns a minio storage +func NewMinioStorage(endpoint, accessKeyID, secretAccessKey, location, bucket, basePath string, useSSL bool) (*MinioStorage, error) { + minioClient, err := minio.New(endpoint, accessKeyID, secretAccessKey, useSSL) + if err != nil { + return nil, err + } + + return &MinioStorage{ + location: location, + client: minioClient, + bucket: bucket, + basePath: basePath, + }, nil +} + +func buildMinioPath(p string) string { + return strings.TrimPrefix(p, "/") +} + +// Open open a file +func (m *MinioStorage) Open(path string) (io.ReadCloser, error) { + var opts = minio.GetObjectOptions{} + object, err := m.client.GetObject(m.bucket, buildMinioPath(path), opts) + if err != nil { + return nil, err + } + return object, nil +} + +// Save save a file to minio +func (m *MinioStorage) Save(path string, r io.Reader) (int64, error) { + return m.client.PutObject(m.bucket, buildMinioPath(path), r, -1, minio.PutObjectOptions{ContentType: "application/octet-stream"}) +} + +// Delete delete a file +func (m *MinioStorage) Delete(path string) error { + return m.client.RemoveObject(m.bucket, buildMinioPath(path)) +} diff --git a/modules/storage/storage.go b/modules/storage/storage.go new file mode 100644 index 0000000000000..5034a7d4b9d54 --- /dev/null +++ b/modules/storage/storage.go @@ -0,0 +1,42 @@ +package storage + +import ( + "io" + + "code.gitea.io/gitea/modules/setting" +) + +// ObjectStorage represents an object storage to handle a bucket and files +type ObjectStorage interface { + Save(path string, r io.Reader) (int64, error) + Open(path string) (io.ReadCloser, error) + Delete(path string) error +} + +// Copy copys a file from source ObjectStorage to dest ObjectStorage +func Copy(dstStorage ObjectStorage, dstPath string, srcStorage ObjectStorage, srcPath string) (int64, error) { + f, err := srcStorage.Open(srcPath) + if err != nil { + return 0, err + } + defer f.Close() + + return dstStorage.Save(dstPath, f) +} + +var ( + // Attachments represents attachments storage + Attachments ObjectStorage +) + +// Init init the stoarge +func Init() error { + var err error + Attachments, err = NewLocalStorage(setting.AttachmentPath) + if err != nil { + return err + } + + return nil +} + diff --git a/routers/init.go b/routers/init.go index c842b5d38e172..2f12058ac5162 100644 --- a/routers/init.go +++ b/routers/init.go @@ -28,6 +28,7 @@ import ( "code.gitea.io/gitea/modules/options" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/ssh" + "code.gitea.io/gitea/modules/storage" "code.gitea.io/gitea/modules/svg" "code.gitea.io/gitea/modules/task" "code.gitea.io/gitea/modules/webhook" @@ -54,6 +55,9 @@ func checkRunMode() { // NewServices init new services func NewServices() { setting.NewServices() + if err := storage.Init(); err != nil { + log.Fatal("storage init failed: %v", err) + } mailer.NewContext() _ = cache.NewContext() notification.NewContext() diff --git a/routers/repo/attachment.go b/routers/repo/attachment.go index 51725100b8444..505468fee5b85 100644 --- a/routers/repo/attachment.go +++ b/routers/repo/attachment.go @@ -7,13 +7,13 @@ package repo import ( "fmt" "net/http" - "os" "strings" "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/storage" "code.gitea.io/gitea/modules/upload" ) @@ -123,7 +123,7 @@ func GetAttachment(ctx *context.Context) { } //If we have matched and access to release or issue - fr, err := os.Open(attach.LocalPath()) + fr, err := storage.Attachments.Open(attach.RelativePath()) if err != nil { ctx.ServerError("Open", err) return diff --git a/services/release/release.go b/services/release/release.go index c308c19f249e0..c36e2126ed782 100644 --- a/services/release/release.go +++ b/services/release/release.go @@ -13,8 +13,8 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/notification" "code.gitea.io/gitea/modules/repository" + "code.gitea.io/gitea/modules/storage" "code.gitea.io/gitea/modules/timeutil" - "code.gitea.io/gitea/modules/util" ) func createTag(gitRepo *git.Repository, rel *models.Release) error { @@ -168,7 +168,7 @@ func DeleteReleaseByID(id int64, doer *models.User, delTag bool) error { for i := range rel.Attachments { attachment := rel.Attachments[i] - if err := util.RemoveAll(attachment.LocalPath()); err != nil { + if err := storage.Attachments.Delete(attachment.RelativePath()); err != nil { log.Error("Delete attachment %s of release %s failed: %v", attachment.UUID, rel.ID, err) } } diff --git a/vendor/github.com/go-ini/ini/.gitignore b/vendor/github.com/go-ini/ini/.gitignore new file mode 100644 index 0000000000000..12411127b39ef --- /dev/null +++ b/vendor/github.com/go-ini/ini/.gitignore @@ -0,0 +1,6 @@ +testdata/conf_out.ini +ini.sublime-project +ini.sublime-workspace +testdata/conf_reflect.ini +.idea +/.vscode diff --git a/vendor/github.com/go-ini/ini/LICENSE b/vendor/github.com/go-ini/ini/LICENSE new file mode 100644 index 0000000000000..d361bbcdf5c98 --- /dev/null +++ b/vendor/github.com/go-ini/ini/LICENSE @@ -0,0 +1,191 @@ +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: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +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 +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 2014 Unknwon + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT 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/github.com/go-ini/ini/Makefile b/vendor/github.com/go-ini/ini/Makefile new file mode 100644 index 0000000000000..f3b0dae2d298d --- /dev/null +++ b/vendor/github.com/go-ini/ini/Makefile @@ -0,0 +1,15 @@ +.PHONY: build test bench vet coverage + +build: vet bench + +test: + go test -v -cover -race + +bench: + go test -v -cover -test.bench=. -test.benchmem + +vet: + go vet + +coverage: + go test -coverprofile=c.out && go tool cover -html=c.out && rm c.out diff --git a/vendor/github.com/go-ini/ini/README.md b/vendor/github.com/go-ini/ini/README.md new file mode 100644 index 0000000000000..5d65658b29415 --- /dev/null +++ b/vendor/github.com/go-ini/ini/README.md @@ -0,0 +1,43 @@ +# INI + +[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/go-ini/ini/Go?logo=github&style=for-the-badge)](https://github.com/go-ini/ini/actions?query=workflow%3AGo) +[![codecov](https://img.shields.io/codecov/c/github/go-ini/ini/master?logo=codecov&style=for-the-badge)](https://codecov.io/gh/go-ini/ini) +[![GoDoc](https://img.shields.io/badge/GoDoc-Reference-blue?style=for-the-badge&logo=go)](https://pkg.go.dev/github.com/go-ini/ini?tab=doc) +[![Sourcegraph](https://img.shields.io/badge/view%20on-Sourcegraph-brightgreen.svg?style=for-the-badge&logo=sourcegraph)](https://sourcegraph.com/github.com/go-ini/ini) + +![](https://avatars0.githubusercontent.com/u/10216035?v=3&s=200) + +Package ini provides INI file read and write functionality in Go. + +## Features + +- Load from multiple data sources(file, `[]byte`, `io.Reader` and `io.ReadCloser`) with overwrites. +- Read with recursion values. +- Read with parent-child sections. +- Read with auto-increment key names. +- Read with multiple-line values. +- Read with tons of helper methods. +- Read and convert values to Go types. +- Read and **WRITE** comments of sections and keys. +- Manipulate sections, keys and comments with ease. +- Keep sections and keys in order as you parse and save. + +## Installation + +The minimum requirement of Go is **1.6**. + +```sh +$ go get gopkg.in/ini.v1 +``` + +Please add `-u` flag to update in the future. + +## Getting Help + +- [Getting Started](https://ini.unknwon.io/docs/intro/getting_started) +- [API Documentation](https://gowalker.org/gopkg.in/ini.v1) +- 中国大陆镜像:https://ini.unknwon.cn + +## License + +This project is under Apache v2 License. See the [LICENSE](LICENSE) file for the full license text. diff --git a/vendor/github.com/go-ini/ini/codecov.yml b/vendor/github.com/go-ini/ini/codecov.yml new file mode 100644 index 0000000000000..fc947f2308201 --- /dev/null +++ b/vendor/github.com/go-ini/ini/codecov.yml @@ -0,0 +1,9 @@ +coverage: + range: "60...95" + status: + project: + default: + threshold: 1% + +comment: + layout: 'diff, files' diff --git a/vendor/github.com/go-ini/ini/data_source.go b/vendor/github.com/go-ini/ini/data_source.go new file mode 100644 index 0000000000000..c3a541f1d1b5c --- /dev/null +++ b/vendor/github.com/go-ini/ini/data_source.go @@ -0,0 +1,76 @@ +// Copyright 2019 Unknwon +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +package ini + +import ( + "bytes" + "fmt" + "io" + "io/ioutil" + "os" +) + +var ( + _ dataSource = (*sourceFile)(nil) + _ dataSource = (*sourceData)(nil) + _ dataSource = (*sourceReadCloser)(nil) +) + +// dataSource is an interface that returns object which can be read and closed. +type dataSource interface { + ReadCloser() (io.ReadCloser, error) +} + +// sourceFile represents an object that contains content on the local file system. +type sourceFile struct { + name string +} + +func (s sourceFile) ReadCloser() (_ io.ReadCloser, err error) { + return os.Open(s.name) +} + +// sourceData represents an object that contains content in memory. +type sourceData struct { + data []byte +} + +func (s *sourceData) ReadCloser() (io.ReadCloser, error) { + return ioutil.NopCloser(bytes.NewReader(s.data)), nil +} + +// sourceReadCloser represents an input stream with Close method. +type sourceReadCloser struct { + reader io.ReadCloser +} + +func (s *sourceReadCloser) ReadCloser() (io.ReadCloser, error) { + return s.reader, nil +} + +func parseDataSource(source interface{}) (dataSource, error) { + switch s := source.(type) { + case string: + return sourceFile{s}, nil + case []byte: + return &sourceData{s}, nil + case io.ReadCloser: + return &sourceReadCloser{s}, nil + case io.Reader: + return &sourceReadCloser{ioutil.NopCloser(s)}, nil + default: + return nil, fmt.Errorf("error parsing data source: unknown type %q", s) + } +} diff --git a/vendor/github.com/go-ini/ini/deprecated.go b/vendor/github.com/go-ini/ini/deprecated.go new file mode 100644 index 0000000000000..e8bda06e6ffee --- /dev/null +++ b/vendor/github.com/go-ini/ini/deprecated.go @@ -0,0 +1,25 @@ +// Copyright 2019 Unknwon +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +package ini + +const ( + // Deprecated: Use "DefaultSection" instead. + DEFAULT_SECTION = DefaultSection +) + +var ( + // Deprecated: AllCapsUnderscore converts to format ALL_CAPS_UNDERSCORE. + AllCapsUnderscore = SnackCase +) diff --git a/vendor/github.com/go-ini/ini/error.go b/vendor/github.com/go-ini/ini/error.go new file mode 100644 index 0000000000000..d88347c54bf62 --- /dev/null +++ b/vendor/github.com/go-ini/ini/error.go @@ -0,0 +1,34 @@ +// Copyright 2016 Unknwon +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +package ini + +import ( + "fmt" +) + +// ErrDelimiterNotFound indicates the error type of no delimiter is found which there should be one. +type ErrDelimiterNotFound struct { + Line string +} + +// IsErrDelimiterNotFound returns true if the given error is an instance of ErrDelimiterNotFound. +func IsErrDelimiterNotFound(err error) bool { + _, ok := err.(ErrDelimiterNotFound) + return ok +} + +func (err ErrDelimiterNotFound) Error() string { + return fmt.Sprintf("key-value delimiter not found: %s", err.Line) +} diff --git a/vendor/github.com/go-ini/ini/file.go b/vendor/github.com/go-ini/ini/file.go new file mode 100644 index 0000000000000..f95606f90fa3d --- /dev/null +++ b/vendor/github.com/go-ini/ini/file.go @@ -0,0 +1,509 @@ +// Copyright 2017 Unknwon +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +package ini + +import ( + "bytes" + "errors" + "fmt" + "io" + "io/ioutil" + "os" + "strings" + "sync" +) + +// File represents a combination of one or more INI files in memory. +type File struct { + options LoadOptions + dataSources []dataSource + + // Should make things safe, but sometimes doesn't matter. + BlockMode bool + lock sync.RWMutex + + // To keep data in order. + sectionList []string + // To keep track of the index of a section with same name. + // This meta list is only used with non-unique section names are allowed. + sectionIndexes []int + + // Actual data is stored here. + sections map[string][]*Section + + NameMapper + ValueMapper +} + +// newFile initializes File object with given data sources. +func newFile(dataSources []dataSource, opts LoadOptions) *File { + if len(opts.KeyValueDelimiters) == 0 { + opts.KeyValueDelimiters = "=:" + } + if len(opts.KeyValueDelimiterOnWrite) == 0 { + opts.KeyValueDelimiterOnWrite = "=" + } + + return &File{ + BlockMode: true, + dataSources: dataSources, + sections: make(map[string][]*Section), + options: opts, + } +} + +// Empty returns an empty file object. +func Empty(opts ...LoadOptions) *File { + var opt LoadOptions + if len(opts) > 0 { + opt = opts[0] + } + + // Ignore error here, we are sure our data is good. + f, _ := LoadSources(opt, []byte("")) + return f +} + +// NewSection creates a new section. +func (f *File) NewSection(name string) (*Section, error) { + if len(name) == 0 { + return nil, errors.New("empty section name") + } + + if f.options.Insensitive && name != DefaultSection { + name = strings.ToLower(name) + } + + if f.BlockMode { + f.lock.Lock() + defer f.lock.Unlock() + } + + if !f.options.AllowNonUniqueSections && inSlice(name, f.sectionList) { + return f.sections[name][0], nil + } + + f.sectionList = append(f.sectionList, name) + + // NOTE: Append to indexes must happen before appending to sections, + // otherwise index will have off-by-one problem. + f.sectionIndexes = append(f.sectionIndexes, len(f.sections[name])) + + sec := newSection(f, name) + f.sections[name] = append(f.sections[name], sec) + + return sec, nil +} + +// NewRawSection creates a new section with an unparseable body. +func (f *File) NewRawSection(name, body string) (*Section, error) { + section, err := f.NewSection(name) + if err != nil { + return nil, err + } + + section.isRawSection = true + section.rawBody = body + return section, nil +} + +// NewSections creates a list of sections. +func (f *File) NewSections(names ...string) (err error) { + for _, name := range names { + if _, err = f.NewSection(name); err != nil { + return err + } + } + return nil +} + +// GetSection returns section by given name. +func (f *File) GetSection(name string) (*Section, error) { + secs, err := f.SectionsByName(name) + if err != nil { + return nil, err + } + + return secs[0], err +} + +// SectionsByName returns all sections with given name. +func (f *File) SectionsByName(name string) ([]*Section, error) { + if len(name) == 0 { + name = DefaultSection + } + if f.options.Insensitive { + name = strings.ToLower(name) + } + + if f.BlockMode { + f.lock.RLock() + defer f.lock.RUnlock() + } + + secs := f.sections[name] + if len(secs) == 0 { + return nil, fmt.Errorf("section %q does not exist", name) + } + + return secs, nil +} + +// Section assumes named section exists and returns a zero-value when not. +func (f *File) Section(name string) *Section { + sec, err := f.GetSection(name) + if err != nil { + // Note: It's OK here because the only possible error is empty section name, + // but if it's empty, this piece of code won't be executed. + sec, _ = f.NewSection(name) + return sec + } + return sec +} + +// SectionWithIndex assumes named section exists and returns a new section when not. +func (f *File) SectionWithIndex(name string, index int) *Section { + secs, err := f.SectionsByName(name) + if err != nil || len(secs) <= index { + // NOTE: It's OK here because the only possible error is empty section name, + // but if it's empty, this piece of code won't be executed. + newSec, _ := f.NewSection(name) + return newSec + } + + return secs[index] +} + +// Sections returns a list of Section stored in the current instance. +func (f *File) Sections() []*Section { + if f.BlockMode { + f.lock.RLock() + defer f.lock.RUnlock() + } + + sections := make([]*Section, len(f.sectionList)) + for i, name := range f.sectionList { + sections[i] = f.sections[name][f.sectionIndexes[i]] + } + return sections +} + +// ChildSections returns a list of child sections of given section name. +func (f *File) ChildSections(name string) []*Section { + return f.Section(name).ChildSections() +} + +// SectionStrings returns list of section names. +func (f *File) SectionStrings() []string { + list := make([]string, len(f.sectionList)) + copy(list, f.sectionList) + return list +} + +// DeleteSection deletes a section or all sections with given name. +func (f *File) DeleteSection(name string) { + secs, err := f.SectionsByName(name) + if err != nil { + return + } + + for i := 0; i < len(secs); i++ { + // For non-unique sections, it is always needed to remove the first one so + // in the next iteration, the subsequent section continue having index 0. + // Ignoring the error as index 0 never returns an error. + _ = f.DeleteSectionWithIndex(name, 0) + } +} + +// DeleteSectionWithIndex deletes a section with given name and index. +func (f *File) DeleteSectionWithIndex(name string, index int) error { + if !f.options.AllowNonUniqueSections && index != 0 { + return fmt.Errorf("delete section with non-zero index is only allowed when non-unique sections is enabled") + } + + if len(name) == 0 { + name = DefaultSection + } + if f.options.Insensitive { + name = strings.ToLower(name) + } + + if f.BlockMode { + f.lock.Lock() + defer f.lock.Unlock() + } + + // Count occurrences of the sections + occurrences := 0 + + sectionListCopy := make([]string, len(f.sectionList)) + copy(sectionListCopy, f.sectionList) + + for i, s := range sectionListCopy { + if s != name { + continue + } + + if occurrences == index { + if len(f.sections[name]) <= 1 { + delete(f.sections, name) // The last one in the map + } else { + f.sections[name] = append(f.sections[name][:index], f.sections[name][index+1:]...) + } + + // Fix section lists + f.sectionList = append(f.sectionList[:i], f.sectionList[i+1:]...) + f.sectionIndexes = append(f.sectionIndexes[:i], f.sectionIndexes[i+1:]...) + + } else if occurrences > index { + // Fix the indices of all following sections with this name. + f.sectionIndexes[i-1]-- + } + + occurrences++ + } + + return nil +} + +func (f *File) reload(s dataSource) error { + r, err := s.ReadCloser() + if err != nil { + return err + } + defer r.Close() + + return f.parse(r) +} + +// Reload reloads and parses all data sources. +func (f *File) Reload() (err error) { + for _, s := range f.dataSources { + if err = f.reload(s); err != nil { + // In loose mode, we create an empty default section for nonexistent files. + if os.IsNotExist(err) && f.options.Loose { + _ = f.parse(bytes.NewBuffer(nil)) + continue + } + return err + } + } + return nil +} + +// Append appends one or more data sources and reloads automatically. +func (f *File) Append(source interface{}, others ...interface{}) error { + ds, err := parseDataSource(source) + if err != nil { + return err + } + f.dataSources = append(f.dataSources, ds) + for _, s := range others { + ds, err = parseDataSource(s) + if err != nil { + return err + } + f.dataSources = append(f.dataSources, ds) + } + return f.Reload() +} + +func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) { + equalSign := DefaultFormatLeft + f.options.KeyValueDelimiterOnWrite + DefaultFormatRight + + if PrettyFormat || PrettyEqual { + equalSign = fmt.Sprintf(" %s ", f.options.KeyValueDelimiterOnWrite) + } + + // Use buffer to make sure target is safe until finish encoding. + buf := bytes.NewBuffer(nil) + for i, sname := range f.sectionList { + sec := f.SectionWithIndex(sname, f.sectionIndexes[i]) + if len(sec.Comment) > 0 { + // Support multiline comments + lines := strings.Split(sec.Comment, LineBreak) + for i := range lines { + if lines[i][0] != '#' && lines[i][0] != ';' { + lines[i] = "; " + lines[i] + } else { + lines[i] = lines[i][:1] + " " + strings.TrimSpace(lines[i][1:]) + } + + if _, err := buf.WriteString(lines[i] + LineBreak); err != nil { + return nil, err + } + } + } + + if i > 0 || DefaultHeader { + if _, err := buf.WriteString("[" + sname + "]" + LineBreak); err != nil { + return nil, err + } + } else { + // Write nothing if default section is empty + if len(sec.keyList) == 0 { + continue + } + } + + if sec.isRawSection { + if _, err := buf.WriteString(sec.rawBody); err != nil { + return nil, err + } + + if PrettySection { + // Put a line between sections + if _, err := buf.WriteString(LineBreak); err != nil { + return nil, err + } + } + continue + } + + // Count and generate alignment length and buffer spaces using the + // longest key. Keys may be modified if they contain certain characters so + // we need to take that into account in our calculation. + alignLength := 0 + if PrettyFormat { + for _, kname := range sec.keyList { + keyLength := len(kname) + // First case will surround key by ` and second by """ + if strings.Contains(kname, "\"") || strings.ContainsAny(kname, f.options.KeyValueDelimiters) { + keyLength += 2 + } else if strings.Contains(kname, "`") { + keyLength += 6 + } + + if keyLength > alignLength { + alignLength = keyLength + } + } + } + alignSpaces := bytes.Repeat([]byte(" "), alignLength) + + KeyList: + for _, kname := range sec.keyList { + key := sec.Key(kname) + if len(key.Comment) > 0 { + if len(indent) > 0 && sname != DefaultSection { + buf.WriteString(indent) + } + + // Support multiline comments + lines := strings.Split(key.Comment, LineBreak) + for i := range lines { + if lines[i][0] != '#' && lines[i][0] != ';' { + lines[i] = "; " + strings.TrimSpace(lines[i]) + } else { + lines[i] = lines[i][:1] + " " + strings.TrimSpace(lines[i][1:]) + } + + if _, err := buf.WriteString(lines[i] + LineBreak); err != nil { + return nil, err + } + } + } + + if len(indent) > 0 && sname != DefaultSection { + buf.WriteString(indent) + } + + switch { + case key.isAutoIncrement: + kname = "-" + case strings.Contains(kname, "\"") || strings.ContainsAny(kname, f.options.KeyValueDelimiters): + kname = "`" + kname + "`" + case strings.Contains(kname, "`"): + kname = `"""` + kname + `"""` + } + + for _, val := range key.ValueWithShadows() { + if _, err := buf.WriteString(kname); err != nil { + return nil, err + } + + if key.isBooleanType { + if kname != sec.keyList[len(sec.keyList)-1] { + buf.WriteString(LineBreak) + } + continue KeyList + } + + // Write out alignment spaces before "=" sign + if PrettyFormat { + buf.Write(alignSpaces[:alignLength-len(kname)]) + } + + // In case key value contains "\n", "`", "\"", "#" or ";" + if strings.ContainsAny(val, "\n`") { + val = `"""` + val + `"""` + } else if !f.options.IgnoreInlineComment && strings.ContainsAny(val, "#;") { + val = "`" + val + "`" + } + if _, err := buf.WriteString(equalSign + val + LineBreak); err != nil { + return nil, err + } + } + + for _, val := range key.nestedValues { + if _, err := buf.WriteString(indent + " " + val + LineBreak); err != nil { + return nil, err + } + } + } + + if PrettySection { + // Put a line between sections + if _, err := buf.WriteString(LineBreak); err != nil { + return nil, err + } + } + } + + return buf, nil +} + +// WriteToIndent writes content into io.Writer with given indention. +// If PrettyFormat has been set to be true, +// it will align "=" sign with spaces under each section. +func (f *File) WriteToIndent(w io.Writer, indent string) (int64, error) { + buf, err := f.writeToBuffer(indent) + if err != nil { + return 0, err + } + return buf.WriteTo(w) +} + +// WriteTo writes file content into io.Writer. +func (f *File) WriteTo(w io.Writer) (int64, error) { + return f.WriteToIndent(w, "") +} + +// SaveToIndent writes content to file system with given value indention. +func (f *File) SaveToIndent(filename, indent string) error { + // Note: Because we are truncating with os.Create, + // so it's safer to save to a temporary file location and rename afte done. + buf, err := f.writeToBuffer(indent) + if err != nil { + return err + } + + return ioutil.WriteFile(filename, buf.Bytes(), 0666) +} + +// SaveTo writes content to file system. +func (f *File) SaveTo(filename string) error { + return f.SaveToIndent(filename, "") +} diff --git a/vendor/github.com/go-ini/ini/helper.go b/vendor/github.com/go-ini/ini/helper.go new file mode 100644 index 0000000000000..f9d80a682a554 --- /dev/null +++ b/vendor/github.com/go-ini/ini/helper.go @@ -0,0 +1,24 @@ +// Copyright 2019 Unknwon +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +package ini + +func inSlice(str string, s []string) bool { + for _, v := range s { + if str == v { + return true + } + } + return false +} diff --git a/vendor/github.com/go-ini/ini/ini.go b/vendor/github.com/go-ini/ini/ini.go new file mode 100644 index 0000000000000..2961543f918b9 --- /dev/null +++ b/vendor/github.com/go-ini/ini/ini.go @@ -0,0 +1,168 @@ +// +build go1.6 + +// Copyright 2014 Unknwon +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +// Package ini provides INI file read and write functionality in Go. +package ini + +import ( + "os" + "regexp" + "runtime" + "strings" +) + +const ( + // DefaultSection is the name of default section. You can use this constant or the string literal. + // In most of cases, an empty string is all you need to access the section. + DefaultSection = "DEFAULT" + + // Maximum allowed depth when recursively substituing variable names. + depthValues = 99 +) + +var ( + // LineBreak is the delimiter to determine or compose a new line. + // This variable will be changed to "\r\n" automatically on Windows at package init time. + LineBreak = "\n" + + // Variable regexp pattern: %(variable)s + varPattern = regexp.MustCompile(`%\(([^)]+)\)s`) + + // DefaultHeader explicitly writes default section header. + DefaultHeader = false + + // PrettySection indicates whether to put a line between sections. + PrettySection = true + // PrettyFormat indicates whether to align "=" sign with spaces to produce pretty output + // or reduce all possible spaces for compact format. + PrettyFormat = true + // PrettyEqual places spaces around "=" sign even when PrettyFormat is false. + PrettyEqual = false + // DefaultFormatLeft places custom spaces on the left when PrettyFormat and PrettyEqual are both disabled. + DefaultFormatLeft = "" + // DefaultFormatRight places custom spaces on the right when PrettyFormat and PrettyEqual are both disabled. + DefaultFormatRight = "" +) + +var inTest = len(os.Args) > 0 && strings.HasSuffix(strings.TrimSuffix(os.Args[0], ".exe"), ".test") + +func init() { + if runtime.GOOS == "windows" && !inTest { + LineBreak = "\r\n" + } +} + +// LoadOptions contains all customized options used for load data source(s). +type LoadOptions struct { + // Loose indicates whether the parser should ignore nonexistent files or return error. + Loose bool + // Insensitive indicates whether the parser forces all section and key names to lowercase. + Insensitive bool + // IgnoreContinuation indicates whether to ignore continuation lines while parsing. + IgnoreContinuation bool + // IgnoreInlineComment indicates whether to ignore comments at the end of value and treat it as part of value. + IgnoreInlineComment bool + // SkipUnrecognizableLines indicates whether to skip unrecognizable lines that do not conform to key/value pairs. + SkipUnrecognizableLines bool + // AllowBooleanKeys indicates whether to allow boolean type keys or treat as value is missing. + // This type of keys are mostly used in my.cnf. + AllowBooleanKeys bool + // AllowShadows indicates whether to keep track of keys with same name under same section. + AllowShadows bool + // AllowNestedValues indicates whether to allow AWS-like nested values. + // Docs: http://docs.aws.amazon.com/cli/latest/topic/config-vars.html#nested-values + AllowNestedValues bool + // AllowPythonMultilineValues indicates whether to allow Python-like multi-line values. + // Docs: https://docs.python.org/3/library/configparser.html#supported-ini-file-structure + // Relevant quote: Values can also span multiple lines, as long as they are indented deeper + // than the first line of the value. + AllowPythonMultilineValues bool + // SpaceBeforeInlineComment indicates whether to allow comment symbols (\# and \;) inside value. + // Docs: https://docs.python.org/2/library/configparser.html + // Quote: Comments may appear on their own in an otherwise empty line, or may be entered in lines holding values or section names. + // In the latter case, they need to be preceded by a whitespace character to be recognized as a comment. + SpaceBeforeInlineComment bool + // UnescapeValueDoubleQuotes indicates whether to unescape double quotes inside value to regular format + // when value is surrounded by double quotes, e.g. key="a \"value\"" => key=a "value" + UnescapeValueDoubleQuotes bool + // UnescapeValueCommentSymbols indicates to unescape comment symbols (\# and \;) inside value to regular format + // when value is NOT surrounded by any quotes. + // Note: UNSTABLE, behavior might change to only unescape inside double quotes but may noy necessary at all. + UnescapeValueCommentSymbols bool + // UnparseableSections stores a list of blocks that are allowed with raw content which do not otherwise + // conform to key/value pairs. Specify the names of those blocks here. + UnparseableSections []string + // KeyValueDelimiters is the sequence of delimiters that are used to separate key and value. By default, it is "=:". + KeyValueDelimiters string + // KeyValueDelimiters is the delimiter that are used to separate key and value output. By default, it is "=". + KeyValueDelimiterOnWrite string + // PreserveSurroundedQuote indicates whether to preserve surrounded quote (single and double quotes). + PreserveSurroundedQuote bool + // DebugFunc is called to collect debug information (currently only useful to debug parsing Python-style multiline values). + DebugFunc DebugFunc + // ReaderBufferSize is the buffer size of the reader in bytes. + ReaderBufferSize int + // AllowNonUniqueSections indicates whether to allow sections with the same name multiple times. + AllowNonUniqueSections bool +} + +// DebugFunc is the type of function called to log parse events. +type DebugFunc func(message string) + +// LoadSources allows caller to apply customized options for loading from data source(s). +func LoadSources(opts LoadOptions, source interface{}, others ...interface{}) (_ *File, err error) { + sources := make([]dataSource, len(others)+1) + sources[0], err = parseDataSource(source) + if err != nil { + return nil, err + } + for i := range others { + sources[i+1], err = parseDataSource(others[i]) + if err != nil { + return nil, err + } + } + f := newFile(sources, opts) + if err = f.Reload(); err != nil { + return nil, err + } + return f, nil +} + +// Load loads and parses from INI data sources. +// Arguments can be mixed of file name with string type, or raw data in []byte. +// It will return error if list contains nonexistent files. +func Load(source interface{}, others ...interface{}) (*File, error) { + return LoadSources(LoadOptions{}, source, others...) +} + +// LooseLoad has exactly same functionality as Load function +// except it ignores nonexistent files instead of returning error. +func LooseLoad(source interface{}, others ...interface{}) (*File, error) { + return LoadSources(LoadOptions{Loose: true}, source, others...) +} + +// InsensitiveLoad has exactly same functionality as Load function +// except it forces all section and key names to be lowercased. +func InsensitiveLoad(source interface{}, others ...interface{}) (*File, error) { + return LoadSources(LoadOptions{Insensitive: true}, source, others...) +} + +// ShadowLoad has exactly same functionality as Load function +// except it allows have shadow keys. +func ShadowLoad(source interface{}, others ...interface{}) (*File, error) { + return LoadSources(LoadOptions{AllowShadows: true}, source, others...) +} diff --git a/vendor/github.com/go-ini/ini/key.go b/vendor/github.com/go-ini/ini/key.go new file mode 100644 index 0000000000000..8baafd9ea6d03 --- /dev/null +++ b/vendor/github.com/go-ini/ini/key.go @@ -0,0 +1,829 @@ +// Copyright 2014 Unknwon +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +package ini + +import ( + "bytes" + "errors" + "fmt" + "strconv" + "strings" + "time" +) + +// Key represents a key under a section. +type Key struct { + s *Section + Comment string + name string + value string + isAutoIncrement bool + isBooleanType bool + + isShadow bool + shadows []*Key + + nestedValues []string +} + +// newKey simply return a key object with given values. +func newKey(s *Section, name, val string) *Key { + return &Key{ + s: s, + name: name, + value: val, + } +} + +func (k *Key) addShadow(val string) error { + if k.isShadow { + return errors.New("cannot add shadow to another shadow key") + } else if k.isAutoIncrement || k.isBooleanType { + return errors.New("cannot add shadow to auto-increment or boolean key") + } + + // Deduplicate shadows based on their values. + if k.value == val { + return nil + } + for i := range k.shadows { + if k.shadows[i].value == val { + return nil + } + } + + shadow := newKey(k.s, k.name, val) + shadow.isShadow = true + k.shadows = append(k.shadows, shadow) + return nil +} + +// AddShadow adds a new shadow key to itself. +func (k *Key) AddShadow(val string) error { + if !k.s.f.options.AllowShadows { + return errors.New("shadow key is not allowed") + } + return k.addShadow(val) +} + +func (k *Key) addNestedValue(val string) error { + if k.isAutoIncrement || k.isBooleanType { + return errors.New("cannot add nested value to auto-increment or boolean key") + } + + k.nestedValues = append(k.nestedValues, val) + return nil +} + +// AddNestedValue adds a nested value to the key. +func (k *Key) AddNestedValue(val string) error { + if !k.s.f.options.AllowNestedValues { + return errors.New("nested value is not allowed") + } + return k.addNestedValue(val) +} + +// ValueMapper represents a mapping function for values, e.g. os.ExpandEnv +type ValueMapper func(string) string + +// Name returns name of key. +func (k *Key) Name() string { + return k.name +} + +// Value returns raw value of key for performance purpose. +func (k *Key) Value() string { + return k.value +} + +// ValueWithShadows returns raw values of key and its shadows if any. +func (k *Key) ValueWithShadows() []string { + if len(k.shadows) == 0 { + return []string{k.value} + } + vals := make([]string, len(k.shadows)+1) + vals[0] = k.value + for i := range k.shadows { + vals[i+1] = k.shadows[i].value + } + return vals +} + +// NestedValues returns nested values stored in the key. +// It is possible returned value is nil if no nested values stored in the key. +func (k *Key) NestedValues() []string { + return k.nestedValues +} + +// transformValue takes a raw value and transforms to its final string. +func (k *Key) transformValue(val string) string { + if k.s.f.ValueMapper != nil { + val = k.s.f.ValueMapper(val) + } + + // Fail-fast if no indicate char found for recursive value + if !strings.Contains(val, "%") { + return val + } + for i := 0; i < depthValues; i++ { + vr := varPattern.FindString(val) + if len(vr) == 0 { + break + } + + // Take off leading '%(' and trailing ')s'. + noption := vr[2 : len(vr)-2] + + // Search in the same section. + // If not found or found the key itself, then search again in default section. + nk, err := k.s.GetKey(noption) + if err != nil || k == nk { + nk, _ = k.s.f.Section("").GetKey(noption) + if nk == nil { + // Stop when no results found in the default section, + // and returns the value as-is. + break + } + } + + // Substitute by new value and take off leading '%(' and trailing ')s'. + val = strings.Replace(val, vr, nk.value, -1) + } + return val +} + +// String returns string representation of value. +func (k *Key) String() string { + return k.transformValue(k.value) +} + +// Validate accepts a validate function which can +// return modifed result as key value. +func (k *Key) Validate(fn func(string) string) string { + return fn(k.String()) +} + +// parseBool returns the boolean value represented by the string. +// +// It accepts 1, t, T, TRUE, true, True, YES, yes, Yes, y, ON, on, On, +// 0, f, F, FALSE, false, False, NO, no, No, n, OFF, off, Off. +// Any other value returns an error. +func parseBool(str string) (value bool, err error) { + switch str { + case "1", "t", "T", "true", "TRUE", "True", "YES", "yes", "Yes", "y", "ON", "on", "On": + return true, nil + case "0", "f", "F", "false", "FALSE", "False", "NO", "no", "No", "n", "OFF", "off", "Off": + return false, nil + } + return false, fmt.Errorf("parsing \"%s\": invalid syntax", str) +} + +// Bool returns bool type value. +func (k *Key) Bool() (bool, error) { + return parseBool(k.String()) +} + +// Float64 returns float64 type value. +func (k *Key) Float64() (float64, error) { + return strconv.ParseFloat(k.String(), 64) +} + +// Int returns int type value. +func (k *Key) Int() (int, error) { + v, err := strconv.ParseInt(k.String(), 0, 64) + return int(v), err +} + +// Int64 returns int64 type value. +func (k *Key) Int64() (int64, error) { + return strconv.ParseInt(k.String(), 0, 64) +} + +// Uint returns uint type valued. +func (k *Key) Uint() (uint, error) { + u, e := strconv.ParseUint(k.String(), 0, 64) + return uint(u), e +} + +// Uint64 returns uint64 type value. +func (k *Key) Uint64() (uint64, error) { + return strconv.ParseUint(k.String(), 0, 64) +} + +// Duration returns time.Duration type value. +func (k *Key) Duration() (time.Duration, error) { + return time.ParseDuration(k.String()) +} + +// TimeFormat parses with given format and returns time.Time type value. +func (k *Key) TimeFormat(format string) (time.Time, error) { + return time.Parse(format, k.String()) +} + +// Time parses with RFC3339 format and returns time.Time type value. +func (k *Key) Time() (time.Time, error) { + return k.TimeFormat(time.RFC3339) +} + +// MustString returns default value if key value is empty. +func (k *Key) MustString(defaultVal string) string { + val := k.String() + if len(val) == 0 { + k.value = defaultVal + return defaultVal + } + return val +} + +// MustBool always returns value without error, +// it returns false if error occurs. +func (k *Key) MustBool(defaultVal ...bool) bool { + val, err := k.Bool() + if len(defaultVal) > 0 && err != nil { + k.value = strconv.FormatBool(defaultVal[0]) + return defaultVal[0] + } + return val +} + +// MustFloat64 always returns value without error, +// it returns 0.0 if error occurs. +func (k *Key) MustFloat64(defaultVal ...float64) float64 { + val, err := k.Float64() + if len(defaultVal) > 0 && err != nil { + k.value = strconv.FormatFloat(defaultVal[0], 'f', -1, 64) + return defaultVal[0] + } + return val +} + +// MustInt always returns value without error, +// it returns 0 if error occurs. +func (k *Key) MustInt(defaultVal ...int) int { + val, err := k.Int() + if len(defaultVal) > 0 && err != nil { + k.value = strconv.FormatInt(int64(defaultVal[0]), 10) + return defaultVal[0] + } + return val +} + +// MustInt64 always returns value without error, +// it returns 0 if error occurs. +func (k *Key) MustInt64(defaultVal ...int64) int64 { + val, err := k.Int64() + if len(defaultVal) > 0 && err != nil { + k.value = strconv.FormatInt(defaultVal[0], 10) + return defaultVal[0] + } + return val +} + +// MustUint always returns value without error, +// it returns 0 if error occurs. +func (k *Key) MustUint(defaultVal ...uint) uint { + val, err := k.Uint() + if len(defaultVal) > 0 && err != nil { + k.value = strconv.FormatUint(uint64(defaultVal[0]), 10) + return defaultVal[0] + } + return val +} + +// MustUint64 always returns value without error, +// it returns 0 if error occurs. +func (k *Key) MustUint64(defaultVal ...uint64) uint64 { + val, err := k.Uint64() + if len(defaultVal) > 0 && err != nil { + k.value = strconv.FormatUint(defaultVal[0], 10) + return defaultVal[0] + } + return val +} + +// MustDuration always returns value without error, +// it returns zero value if error occurs. +func (k *Key) MustDuration(defaultVal ...time.Duration) time.Duration { + val, err := k.Duration() + if len(defaultVal) > 0 && err != nil { + k.value = defaultVal[0].String() + return defaultVal[0] + } + return val +} + +// MustTimeFormat always parses with given format and returns value without error, +// it returns zero value if error occurs. +func (k *Key) MustTimeFormat(format string, defaultVal ...time.Time) time.Time { + val, err := k.TimeFormat(format) + if len(defaultVal) > 0 && err != nil { + k.value = defaultVal[0].Format(format) + return defaultVal[0] + } + return val +} + +// MustTime always parses with RFC3339 format and returns value without error, +// it returns zero value if error occurs. +func (k *Key) MustTime(defaultVal ...time.Time) time.Time { + return k.MustTimeFormat(time.RFC3339, defaultVal...) +} + +// In always returns value without error, +// it returns default value if error occurs or doesn't fit into candidates. +func (k *Key) In(defaultVal string, candidates []string) string { + val := k.String() + for _, cand := range candidates { + if val == cand { + return val + } + } + return defaultVal +} + +// InFloat64 always returns value without error, +// it returns default value if error occurs or doesn't fit into candidates. +func (k *Key) InFloat64(defaultVal float64, candidates []float64) float64 { + val := k.MustFloat64() + for _, cand := range candidates { + if val == cand { + return val + } + } + return defaultVal +} + +// InInt always returns value without error, +// it returns default value if error occurs or doesn't fit into candidates. +func (k *Key) InInt(defaultVal int, candidates []int) int { + val := k.MustInt() + for _, cand := range candidates { + if val == cand { + return val + } + } + return defaultVal +} + +// InInt64 always returns value without error, +// it returns default value if error occurs or doesn't fit into candidates. +func (k *Key) InInt64(defaultVal int64, candidates []int64) int64 { + val := k.MustInt64() + for _, cand := range candidates { + if val == cand { + return val + } + } + return defaultVal +} + +// InUint always returns value without error, +// it returns default value if error occurs or doesn't fit into candidates. +func (k *Key) InUint(defaultVal uint, candidates []uint) uint { + val := k.MustUint() + for _, cand := range candidates { + if val == cand { + return val + } + } + return defaultVal +} + +// InUint64 always returns value without error, +// it returns default value if error occurs or doesn't fit into candidates. +func (k *Key) InUint64(defaultVal uint64, candidates []uint64) uint64 { + val := k.MustUint64() + for _, cand := range candidates { + if val == cand { + return val + } + } + return defaultVal +} + +// InTimeFormat always parses with given format and returns value without error, +// it returns default value if error occurs or doesn't fit into candidates. +func (k *Key) InTimeFormat(format string, defaultVal time.Time, candidates []time.Time) time.Time { + val := k.MustTimeFormat(format) + for _, cand := range candidates { + if val == cand { + return val + } + } + return defaultVal +} + +// InTime always parses with RFC3339 format and returns value without error, +// it returns default value if error occurs or doesn't fit into candidates. +func (k *Key) InTime(defaultVal time.Time, candidates []time.Time) time.Time { + return k.InTimeFormat(time.RFC3339, defaultVal, candidates) +} + +// RangeFloat64 checks if value is in given range inclusively, +// and returns default value if it's not. +func (k *Key) RangeFloat64(defaultVal, min, max float64) float64 { + val := k.MustFloat64() + if val < min || val > max { + return defaultVal + } + return val +} + +// RangeInt checks if value is in given range inclusively, +// and returns default value if it's not. +func (k *Key) RangeInt(defaultVal, min, max int) int { + val := k.MustInt() + if val < min || val > max { + return defaultVal + } + return val +} + +// RangeInt64 checks if value is in given range inclusively, +// and returns default value if it's not. +func (k *Key) RangeInt64(defaultVal, min, max int64) int64 { + val := k.MustInt64() + if val < min || val > max { + return defaultVal + } + return val +} + +// RangeTimeFormat checks if value with given format is in given range inclusively, +// and returns default value if it's not. +func (k *Key) RangeTimeFormat(format string, defaultVal, min, max time.Time) time.Time { + val := k.MustTimeFormat(format) + if val.Unix() < min.Unix() || val.Unix() > max.Unix() { + return defaultVal + } + return val +} + +// RangeTime checks if value with RFC3339 format is in given range inclusively, +// and returns default value if it's not. +func (k *Key) RangeTime(defaultVal, min, max time.Time) time.Time { + return k.RangeTimeFormat(time.RFC3339, defaultVal, min, max) +} + +// Strings returns list of string divided by given delimiter. +func (k *Key) Strings(delim string) []string { + str := k.String() + if len(str) == 0 { + return []string{} + } + + runes := []rune(str) + vals := make([]string, 0, 2) + var buf bytes.Buffer + escape := false + idx := 0 + for { + if escape { + escape = false + if runes[idx] != '\\' && !strings.HasPrefix(string(runes[idx:]), delim) { + buf.WriteRune('\\') + } + buf.WriteRune(runes[idx]) + } else { + if runes[idx] == '\\' { + escape = true + } else if strings.HasPrefix(string(runes[idx:]), delim) { + idx += len(delim) - 1 + vals = append(vals, strings.TrimSpace(buf.String())) + buf.Reset() + } else { + buf.WriteRune(runes[idx]) + } + } + idx++ + if idx == len(runes) { + break + } + } + + if buf.Len() > 0 { + vals = append(vals, strings.TrimSpace(buf.String())) + } + + return vals +} + +// StringsWithShadows returns list of string divided by given delimiter. +// Shadows will also be appended if any. +func (k *Key) StringsWithShadows(delim string) []string { + vals := k.ValueWithShadows() + results := make([]string, 0, len(vals)*2) + for i := range vals { + if len(vals) == 0 { + continue + } + + results = append(results, strings.Split(vals[i], delim)...) + } + + for i := range results { + results[i] = k.transformValue(strings.TrimSpace(results[i])) + } + return results +} + +// Float64s returns list of float64 divided by given delimiter. Any invalid input will be treated as zero value. +func (k *Key) Float64s(delim string) []float64 { + vals, _ := k.parseFloat64s(k.Strings(delim), true, false) + return vals +} + +// Ints returns list of int divided by given delimiter. Any invalid input will be treated as zero value. +func (k *Key) Ints(delim string) []int { + vals, _ := k.parseInts(k.Strings(delim), true, false) + return vals +} + +// Int64s returns list of int64 divided by given delimiter. Any invalid input will be treated as zero value. +func (k *Key) Int64s(delim string) []int64 { + vals, _ := k.parseInt64s(k.Strings(delim), true, false) + return vals +} + +// Uints returns list of uint divided by given delimiter. Any invalid input will be treated as zero value. +func (k *Key) Uints(delim string) []uint { + vals, _ := k.parseUints(k.Strings(delim), true, false) + return vals +} + +// Uint64s returns list of uint64 divided by given delimiter. Any invalid input will be treated as zero value. +func (k *Key) Uint64s(delim string) []uint64 { + vals, _ := k.parseUint64s(k.Strings(delim), true, false) + return vals +} + +// Bools returns list of bool divided by given delimiter. Any invalid input will be treated as zero value. +func (k *Key) Bools(delim string) []bool { + vals, _ := k.parseBools(k.Strings(delim), true, false) + return vals +} + +// TimesFormat parses with given format and returns list of time.Time divided by given delimiter. +// Any invalid input will be treated as zero value (0001-01-01 00:00:00 +0000 UTC). +func (k *Key) TimesFormat(format, delim string) []time.Time { + vals, _ := k.parseTimesFormat(format, k.Strings(delim), true, false) + return vals +} + +// Times parses with RFC3339 format and returns list of time.Time divided by given delimiter. +// Any invalid input will be treated as zero value (0001-01-01 00:00:00 +0000 UTC). +func (k *Key) Times(delim string) []time.Time { + return k.TimesFormat(time.RFC3339, delim) +} + +// ValidFloat64s returns list of float64 divided by given delimiter. If some value is not float, then +// it will not be included to result list. +func (k *Key) ValidFloat64s(delim string) []float64 { + vals, _ := k.parseFloat64s(k.Strings(delim), false, false) + return vals +} + +// ValidInts returns list of int divided by given delimiter. If some value is not integer, then it will +// not be included to result list. +func (k *Key) ValidInts(delim string) []int { + vals, _ := k.parseInts(k.Strings(delim), false, false) + return vals +} + +// ValidInt64s returns list of int64 divided by given delimiter. If some value is not 64-bit integer, +// then it will not be included to result list. +func (k *Key) ValidInt64s(delim string) []int64 { + vals, _ := k.parseInt64s(k.Strings(delim), false, false) + return vals +} + +// ValidUints returns list of uint divided by given delimiter. If some value is not unsigned integer, +// then it will not be included to result list. +func (k *Key) ValidUints(delim string) []uint { + vals, _ := k.parseUints(k.Strings(delim), false, false) + return vals +} + +// ValidUint64s returns list of uint64 divided by given delimiter. If some value is not 64-bit unsigned +// integer, then it will not be included to result list. +func (k *Key) ValidUint64s(delim string) []uint64 { + vals, _ := k.parseUint64s(k.Strings(delim), false, false) + return vals +} + +// ValidBools returns list of bool divided by given delimiter. If some value is not 64-bit unsigned +// integer, then it will not be included to result list. +func (k *Key) ValidBools(delim string) []bool { + vals, _ := k.parseBools(k.Strings(delim), false, false) + return vals +} + +// ValidTimesFormat parses with given format and returns list of time.Time divided by given delimiter. +func (k *Key) ValidTimesFormat(format, delim string) []time.Time { + vals, _ := k.parseTimesFormat(format, k.Strings(delim), false, false) + return vals +} + +// ValidTimes parses with RFC3339 format and returns list of time.Time divided by given delimiter. +func (k *Key) ValidTimes(delim string) []time.Time { + return k.ValidTimesFormat(time.RFC3339, delim) +} + +// StrictFloat64s returns list of float64 divided by given delimiter or error on first invalid input. +func (k *Key) StrictFloat64s(delim string) ([]float64, error) { + return k.parseFloat64s(k.Strings(delim), false, true) +} + +// StrictInts returns list of int divided by given delimiter or error on first invalid input. +func (k *Key) StrictInts(delim string) ([]int, error) { + return k.parseInts(k.Strings(delim), false, true) +} + +// StrictInt64s returns list of int64 divided by given delimiter or error on first invalid input. +func (k *Key) StrictInt64s(delim string) ([]int64, error) { + return k.parseInt64s(k.Strings(delim), false, true) +} + +// StrictUints returns list of uint divided by given delimiter or error on first invalid input. +func (k *Key) StrictUints(delim string) ([]uint, error) { + return k.parseUints(k.Strings(delim), false, true) +} + +// StrictUint64s returns list of uint64 divided by given delimiter or error on first invalid input. +func (k *Key) StrictUint64s(delim string) ([]uint64, error) { + return k.parseUint64s(k.Strings(delim), false, true) +} + +// StrictBools returns list of bool divided by given delimiter or error on first invalid input. +func (k *Key) StrictBools(delim string) ([]bool, error) { + return k.parseBools(k.Strings(delim), false, true) +} + +// StrictTimesFormat parses with given format and returns list of time.Time divided by given delimiter +// or error on first invalid input. +func (k *Key) StrictTimesFormat(format, delim string) ([]time.Time, error) { + return k.parseTimesFormat(format, k.Strings(delim), false, true) +} + +// StrictTimes parses with RFC3339 format and returns list of time.Time divided by given delimiter +// or error on first invalid input. +func (k *Key) StrictTimes(delim string) ([]time.Time, error) { + return k.StrictTimesFormat(time.RFC3339, delim) +} + +// parseBools transforms strings to bools. +func (k *Key) parseBools(strs []string, addInvalid, returnOnInvalid bool) ([]bool, error) { + vals := make([]bool, 0, len(strs)) + parser := func(str string) (interface{}, error) { + val, err := parseBool(str) + return val, err + } + rawVals, err := k.doParse(strs, addInvalid, returnOnInvalid, parser) + if err == nil { + for _, val := range rawVals { + vals = append(vals, val.(bool)) + } + } + return vals, err +} + +// parseFloat64s transforms strings to float64s. +func (k *Key) parseFloat64s(strs []string, addInvalid, returnOnInvalid bool) ([]float64, error) { + vals := make([]float64, 0, len(strs)) + parser := func(str string) (interface{}, error) { + val, err := strconv.ParseFloat(str, 64) + return val, err + } + rawVals, err := k.doParse(strs, addInvalid, returnOnInvalid, parser) + if err == nil { + for _, val := range rawVals { + vals = append(vals, val.(float64)) + } + } + return vals, err +} + +// parseInts transforms strings to ints. +func (k *Key) parseInts(strs []string, addInvalid, returnOnInvalid bool) ([]int, error) { + vals := make([]int, 0, len(strs)) + parser := func(str string) (interface{}, error) { + val, err := strconv.ParseInt(str, 0, 64) + return val, err + } + rawVals, err := k.doParse(strs, addInvalid, returnOnInvalid, parser) + if err == nil { + for _, val := range rawVals { + vals = append(vals, int(val.(int64))) + } + } + return vals, err +} + +// parseInt64s transforms strings to int64s. +func (k *Key) parseInt64s(strs []string, addInvalid, returnOnInvalid bool) ([]int64, error) { + vals := make([]int64, 0, len(strs)) + parser := func(str string) (interface{}, error) { + val, err := strconv.ParseInt(str, 0, 64) + return val, err + } + + rawVals, err := k.doParse(strs, addInvalid, returnOnInvalid, parser) + if err == nil { + for _, val := range rawVals { + vals = append(vals, val.(int64)) + } + } + return vals, err +} + +// parseUints transforms strings to uints. +func (k *Key) parseUints(strs []string, addInvalid, returnOnInvalid bool) ([]uint, error) { + vals := make([]uint, 0, len(strs)) + parser := func(str string) (interface{}, error) { + val, err := strconv.ParseUint(str, 0, 64) + return val, err + } + + rawVals, err := k.doParse(strs, addInvalid, returnOnInvalid, parser) + if err == nil { + for _, val := range rawVals { + vals = append(vals, uint(val.(uint64))) + } + } + return vals, err +} + +// parseUint64s transforms strings to uint64s. +func (k *Key) parseUint64s(strs []string, addInvalid, returnOnInvalid bool) ([]uint64, error) { + vals := make([]uint64, 0, len(strs)) + parser := func(str string) (interface{}, error) { + val, err := strconv.ParseUint(str, 0, 64) + return val, err + } + rawVals, err := k.doParse(strs, addInvalid, returnOnInvalid, parser) + if err == nil { + for _, val := range rawVals { + vals = append(vals, val.(uint64)) + } + } + return vals, err +} + + +type Parser func(str string) (interface{}, error) + + +// parseTimesFormat transforms strings to times in given format. +func (k *Key) parseTimesFormat(format string, strs []string, addInvalid, returnOnInvalid bool) ([]time.Time, error) { + vals := make([]time.Time, 0, len(strs)) + parser := func(str string) (interface{}, error) { + val, err := time.Parse(format, str) + return val, err + } + rawVals, err := k.doParse(strs, addInvalid, returnOnInvalid, parser) + if err == nil { + for _, val := range rawVals { + vals = append(vals, val.(time.Time)) + } + } + return vals, err +} + + +// doParse transforms strings to different types +func (k *Key) doParse(strs []string, addInvalid, returnOnInvalid bool, parser Parser) ([]interface{}, error) { + vals := make([]interface{}, 0, len(strs)) + for _, str := range strs { + val, err := parser(str) + if err != nil && returnOnInvalid { + return nil, err + } + if err == nil || addInvalid { + vals = append(vals, val) + } + } + return vals, nil +} + +// SetValue changes key value. +func (k *Key) SetValue(v string) { + if k.s.f.BlockMode { + k.s.f.lock.Lock() + defer k.s.f.lock.Unlock() + } + + k.value = v + k.s.keysHash[k.name] = v +} diff --git a/vendor/github.com/go-ini/ini/parser.go b/vendor/github.com/go-ini/ini/parser.go new file mode 100644 index 0000000000000..ea6c08b02918c --- /dev/null +++ b/vendor/github.com/go-ini/ini/parser.go @@ -0,0 +1,535 @@ +// Copyright 2015 Unknwon +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +package ini + +import ( + "bufio" + "bytes" + "fmt" + "io" + "regexp" + "strconv" + "strings" + "unicode" +) + +const minReaderBufferSize = 4096 + +var pythonMultiline = regexp.MustCompile(`^([\t\f ]+)(.*)`) + +type parserOptions struct { + IgnoreContinuation bool + IgnoreInlineComment bool + AllowPythonMultilineValues bool + SpaceBeforeInlineComment bool + UnescapeValueDoubleQuotes bool + UnescapeValueCommentSymbols bool + PreserveSurroundedQuote bool + DebugFunc DebugFunc + ReaderBufferSize int +} + +type parser struct { + buf *bufio.Reader + options parserOptions + + isEOF bool + count int + comment *bytes.Buffer +} + +func (p *parser) debug(format string, args ...interface{}) { + if p.options.DebugFunc != nil { + p.options.DebugFunc(fmt.Sprintf(format, args...)) + } +} + +func newParser(r io.Reader, opts parserOptions) *parser { + size := opts.ReaderBufferSize + if size < minReaderBufferSize { + size = minReaderBufferSize + } + + return &parser{ + buf: bufio.NewReaderSize(r, size), + options: opts, + count: 1, + comment: &bytes.Buffer{}, + } +} + +// BOM handles header of UTF-8, UTF-16 LE and UTF-16 BE's BOM format. +// http://en.wikipedia.org/wiki/Byte_order_mark#Representations_of_byte_order_marks_by_encoding +func (p *parser) BOM() error { + mask, err := p.buf.Peek(2) + if err != nil && err != io.EOF { + return err + } else if len(mask) < 2 { + return nil + } + + switch { + case mask[0] == 254 && mask[1] == 255: + fallthrough + case mask[0] == 255 && mask[1] == 254: + _, err = p.buf.Read(mask) + if err != nil { + return err + } + case mask[0] == 239 && mask[1] == 187: + mask, err := p.buf.Peek(3) + if err != nil && err != io.EOF { + return err + } else if len(mask) < 3 { + return nil + } + if mask[2] == 191 { + _, err = p.buf.Read(mask) + if err != nil { + return err + } + } + } + return nil +} + +func (p *parser) readUntil(delim byte) ([]byte, error) { + data, err := p.buf.ReadBytes(delim) + if err != nil { + if err == io.EOF { + p.isEOF = true + } else { + return nil, err + } + } + return data, nil +} + +func cleanComment(in []byte) ([]byte, bool) { + i := bytes.IndexAny(in, "#;") + if i == -1 { + return nil, false + } + return in[i:], true +} + +func readKeyName(delimiters string, in []byte) (string, int, error) { + line := string(in) + + // Check if key name surrounded by quotes. + var keyQuote string + if line[0] == '"' { + if len(line) > 6 && string(line[0:3]) == `"""` { + keyQuote = `"""` + } else { + keyQuote = `"` + } + } else if line[0] == '`' { + keyQuote = "`" + } + + // Get out key name + var endIdx int + if len(keyQuote) > 0 { + startIdx := len(keyQuote) + // FIXME: fail case -> """"""name"""=value + pos := strings.Index(line[startIdx:], keyQuote) + if pos == -1 { + return "", -1, fmt.Errorf("missing closing key quote: %s", line) + } + pos += startIdx + + // Find key-value delimiter + i := strings.IndexAny(line[pos+startIdx:], delimiters) + if i < 0 { + return "", -1, ErrDelimiterNotFound{line} + } + endIdx = pos + i + return strings.TrimSpace(line[startIdx:pos]), endIdx + startIdx + 1, nil + } + + endIdx = strings.IndexAny(line, delimiters) + if endIdx < 0 { + return "", -1, ErrDelimiterNotFound{line} + } + return strings.TrimSpace(line[0:endIdx]), endIdx + 1, nil +} + +func (p *parser) readMultilines(line, val, valQuote string) (string, error) { + for { + data, err := p.readUntil('\n') + if err != nil { + return "", err + } + next := string(data) + + pos := strings.LastIndex(next, valQuote) + if pos > -1 { + val += next[:pos] + + comment, has := cleanComment([]byte(next[pos:])) + if has { + p.comment.Write(bytes.TrimSpace(comment)) + } + break + } + val += next + if p.isEOF { + return "", fmt.Errorf("missing closing key quote from %q to %q", line, next) + } + } + return val, nil +} + +func (p *parser) readContinuationLines(val string) (string, error) { + for { + data, err := p.readUntil('\n') + if err != nil { + return "", err + } + next := strings.TrimSpace(string(data)) + + if len(next) == 0 { + break + } + val += next + if val[len(val)-1] != '\\' { + break + } + val = val[:len(val)-1] + } + return val, nil +} + +// hasSurroundedQuote check if and only if the first and last characters +// are quotes \" or \'. +// It returns false if any other parts also contain same kind of quotes. +func hasSurroundedQuote(in string, quote byte) bool { + return len(in) >= 2 && in[0] == quote && in[len(in)-1] == quote && + strings.IndexByte(in[1:], quote) == len(in)-2 +} + +func (p *parser) readValue(in []byte, bufferSize int) (string, error) { + + line := strings.TrimLeftFunc(string(in), unicode.IsSpace) + if len(line) == 0 { + if p.options.AllowPythonMultilineValues && len(in) > 0 && in[len(in)-1] == '\n' { + return p.readPythonMultilines(line, bufferSize) + } + return "", nil + } + + var valQuote string + if len(line) > 3 && string(line[0:3]) == `"""` { + valQuote = `"""` + } else if line[0] == '`' { + valQuote = "`" + } else if p.options.UnescapeValueDoubleQuotes && line[0] == '"' { + valQuote = `"` + } + + if len(valQuote) > 0 { + startIdx := len(valQuote) + pos := strings.LastIndex(line[startIdx:], valQuote) + // Check for multi-line value + if pos == -1 { + return p.readMultilines(line, line[startIdx:], valQuote) + } + + if p.options.UnescapeValueDoubleQuotes && valQuote == `"` { + return strings.Replace(line[startIdx:pos+startIdx], `\"`, `"`, -1), nil + } + return line[startIdx : pos+startIdx], nil + } + + lastChar := line[len(line)-1] + // Won't be able to reach here if value only contains whitespace + line = strings.TrimSpace(line) + trimmedLastChar := line[len(line)-1] + + // Check continuation lines when desired + if !p.options.IgnoreContinuation && trimmedLastChar == '\\' { + return p.readContinuationLines(line[:len(line)-1]) + } + + // Check if ignore inline comment + if !p.options.IgnoreInlineComment { + var i int + if p.options.SpaceBeforeInlineComment { + i = strings.Index(line, " #") + if i == -1 { + i = strings.Index(line, " ;") + } + + } else { + i = strings.IndexAny(line, "#;") + } + + if i > -1 { + p.comment.WriteString(line[i:]) + line = strings.TrimSpace(line[:i]) + } + + } + + // Trim single and double quotes + if (hasSurroundedQuote(line, '\'') || + hasSurroundedQuote(line, '"')) && !p.options.PreserveSurroundedQuote { + line = line[1 : len(line)-1] + } else if len(valQuote) == 0 && p.options.UnescapeValueCommentSymbols { + if strings.Contains(line, `\;`) { + line = strings.Replace(line, `\;`, ";", -1) + } + if strings.Contains(line, `\#`) { + line = strings.Replace(line, `\#`, "#", -1) + } + } else if p.options.AllowPythonMultilineValues && lastChar == '\n' { + return p.readPythonMultilines(line, bufferSize) + } + + return line, nil +} + +func (p *parser) readPythonMultilines(line string, bufferSize int) (string, error) { + parserBufferPeekResult, _ := p.buf.Peek(bufferSize) + peekBuffer := bytes.NewBuffer(parserBufferPeekResult) + + indentSize := 0 + for { + peekData, peekErr := peekBuffer.ReadBytes('\n') + if peekErr != nil { + if peekErr == io.EOF { + p.debug("readPythonMultilines: io.EOF, peekData: %q, line: %q", string(peekData), line) + return line, nil + } + + p.debug("readPythonMultilines: failed to peek with error: %v", peekErr) + return "", peekErr + } + + p.debug("readPythonMultilines: parsing %q", string(peekData)) + + peekMatches := pythonMultiline.FindStringSubmatch(string(peekData)) + p.debug("readPythonMultilines: matched %d parts", len(peekMatches)) + for n, v := range peekMatches { + p.debug(" %d: %q", n, v) + } + + // Return if not a Python multiline value. + if len(peekMatches) != 3 { + p.debug("readPythonMultilines: end of value, got: %q", line) + return line, nil + } + + // Determine indent size and line prefix. + currentIndentSize := len(peekMatches[1]) + if indentSize < 1 { + indentSize = currentIndentSize + p.debug("readPythonMultilines: indent size is %d", indentSize) + } + + // Make sure each line is indented at least as far as first line. + if currentIndentSize < indentSize { + p.debug("readPythonMultilines: end of value, current indent: %d, expected indent: %d, line: %q", currentIndentSize, indentSize, line) + return line, nil + } + + // Advance the parser reader (buffer) in-sync with the peek buffer. + _, err := p.buf.Discard(len(peekData)) + if err != nil { + p.debug("readPythonMultilines: failed to skip to the end, returning error") + return "", err + } + + // Handle indented empty line. + line += "\n" + peekMatches[1][indentSize:] + peekMatches[2] + } +} + +// parse parses data through an io.Reader. +func (f *File) parse(reader io.Reader) (err error) { + p := newParser(reader, parserOptions{ + IgnoreContinuation: f.options.IgnoreContinuation, + IgnoreInlineComment: f.options.IgnoreInlineComment, + AllowPythonMultilineValues: f.options.AllowPythonMultilineValues, + SpaceBeforeInlineComment: f.options.SpaceBeforeInlineComment, + UnescapeValueDoubleQuotes: f.options.UnescapeValueDoubleQuotes, + UnescapeValueCommentSymbols: f.options.UnescapeValueCommentSymbols, + PreserveSurroundedQuote: f.options.PreserveSurroundedQuote, + DebugFunc: f.options.DebugFunc, + ReaderBufferSize: f.options.ReaderBufferSize, + }) + if err = p.BOM(); err != nil { + return fmt.Errorf("BOM: %v", err) + } + + // Ignore error because default section name is never empty string. + name := DefaultSection + if f.options.Insensitive { + name = strings.ToLower(DefaultSection) + } + section, _ := f.NewSection(name) + + // This "last" is not strictly equivalent to "previous one" if current key is not the first nested key + var isLastValueEmpty bool + var lastRegularKey *Key + + var line []byte + var inUnparseableSection bool + + // NOTE: Iterate and increase `currentPeekSize` until + // the size of the parser buffer is found. + // TODO(unknwon): When Golang 1.10 is the lowest version supported, replace with `parserBufferSize := p.buf.Size()`. + parserBufferSize := 0 + // NOTE: Peek 4kb at a time. + currentPeekSize := minReaderBufferSize + + if f.options.AllowPythonMultilineValues { + for { + peekBytes, _ := p.buf.Peek(currentPeekSize) + peekBytesLength := len(peekBytes) + + if parserBufferSize >= peekBytesLength { + break + } + + currentPeekSize *= 2 + parserBufferSize = peekBytesLength + } + } + + for !p.isEOF { + line, err = p.readUntil('\n') + if err != nil { + return err + } + + if f.options.AllowNestedValues && + isLastValueEmpty && len(line) > 0 { + if line[0] == ' ' || line[0] == '\t' { + err = lastRegularKey.addNestedValue(string(bytes.TrimSpace(line))) + if err != nil { + return err + } + continue + } + } + + line = bytes.TrimLeftFunc(line, unicode.IsSpace) + if len(line) == 0 { + continue + } + + // Comments + if line[0] == '#' || line[0] == ';' { + // Note: we do not care ending line break, + // it is needed for adding second line, + // so just clean it once at the end when set to value. + p.comment.Write(line) + continue + } + + // Section + if line[0] == '[' { + // Read to the next ']' (TODO: support quoted strings) + closeIdx := bytes.LastIndexByte(line, ']') + if closeIdx == -1 { + return fmt.Errorf("unclosed section: %s", line) + } + + name := string(line[1:closeIdx]) + section, err = f.NewSection(name) + if err != nil { + return err + } + + comment, has := cleanComment(line[closeIdx+1:]) + if has { + p.comment.Write(comment) + } + + section.Comment = strings.TrimSpace(p.comment.String()) + + // Reset auto-counter and comments + p.comment.Reset() + p.count = 1 + + inUnparseableSection = false + for i := range f.options.UnparseableSections { + if f.options.UnparseableSections[i] == name || + (f.options.Insensitive && strings.EqualFold(f.options.UnparseableSections[i], name)) { + inUnparseableSection = true + continue + } + } + continue + } + + if inUnparseableSection { + section.isRawSection = true + section.rawBody += string(line) + continue + } + + kname, offset, err := readKeyName(f.options.KeyValueDelimiters, line) + if err != nil { + // Treat as boolean key when desired, and whole line is key name. + if IsErrDelimiterNotFound(err) { + switch { + case f.options.AllowBooleanKeys: + kname, err := p.readValue(line, parserBufferSize) + if err != nil { + return err + } + key, err := section.NewBooleanKey(kname) + if err != nil { + return err + } + key.Comment = strings.TrimSpace(p.comment.String()) + p.comment.Reset() + continue + + case f.options.SkipUnrecognizableLines: + continue + } + } + return err + } + + // Auto increment. + isAutoIncr := false + if kname == "-" { + isAutoIncr = true + kname = "#" + strconv.Itoa(p.count) + p.count++ + } + + value, err := p.readValue(line[offset:], parserBufferSize) + if err != nil { + return err + } + isLastValueEmpty = len(value) == 0 + + key, err := section.NewKey(kname, value) + if err != nil { + return err + } + key.isAutoIncrement = isAutoIncr + key.Comment = strings.TrimSpace(p.comment.String()) + p.comment.Reset() + lastRegularKey = key + } + return nil +} diff --git a/vendor/github.com/go-ini/ini/section.go b/vendor/github.com/go-ini/ini/section.go new file mode 100644 index 0000000000000..6ba5ac2905c83 --- /dev/null +++ b/vendor/github.com/go-ini/ini/section.go @@ -0,0 +1,256 @@ +// Copyright 2014 Unknwon +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +package ini + +import ( + "errors" + "fmt" + "strings" +) + +// Section represents a config section. +type Section struct { + f *File + Comment string + name string + keys map[string]*Key + keyList []string + keysHash map[string]string + + isRawSection bool + rawBody string +} + +func newSection(f *File, name string) *Section { + return &Section{ + f: f, + name: name, + keys: make(map[string]*Key), + keyList: make([]string, 0, 10), + keysHash: make(map[string]string), + } +} + +// Name returns name of Section. +func (s *Section) Name() string { + return s.name +} + +// Body returns rawBody of Section if the section was marked as unparseable. +// It still follows the other rules of the INI format surrounding leading/trailing whitespace. +func (s *Section) Body() string { + return strings.TrimSpace(s.rawBody) +} + +// SetBody updates body content only if section is raw. +func (s *Section) SetBody(body string) { + if !s.isRawSection { + return + } + s.rawBody = body +} + +// NewKey creates a new key to given section. +func (s *Section) NewKey(name, val string) (*Key, error) { + if len(name) == 0 { + return nil, errors.New("error creating new key: empty key name") + } else if s.f.options.Insensitive { + name = strings.ToLower(name) + } + + if s.f.BlockMode { + s.f.lock.Lock() + defer s.f.lock.Unlock() + } + + if inSlice(name, s.keyList) { + if s.f.options.AllowShadows { + if err := s.keys[name].addShadow(val); err != nil { + return nil, err + } + } else { + s.keys[name].value = val + s.keysHash[name] = val + } + return s.keys[name], nil + } + + s.keyList = append(s.keyList, name) + s.keys[name] = newKey(s, name, val) + s.keysHash[name] = val + return s.keys[name], nil +} + +// NewBooleanKey creates a new boolean type key to given section. +func (s *Section) NewBooleanKey(name string) (*Key, error) { + key, err := s.NewKey(name, "true") + if err != nil { + return nil, err + } + + key.isBooleanType = true + return key, nil +} + +// GetKey returns key in section by given name. +func (s *Section) GetKey(name string) (*Key, error) { + if s.f.BlockMode { + s.f.lock.RLock() + } + if s.f.options.Insensitive { + name = strings.ToLower(name) + } + key := s.keys[name] + if s.f.BlockMode { + s.f.lock.RUnlock() + } + + if key == nil { + // Check if it is a child-section. + sname := s.name + for { + if i := strings.LastIndex(sname, "."); i > -1 { + sname = sname[:i] + sec, err := s.f.GetSection(sname) + if err != nil { + continue + } + return sec.GetKey(name) + } + break + } + return nil, fmt.Errorf("error when getting key of section %q: key %q not exists", s.name, name) + } + return key, nil +} + +// HasKey returns true if section contains a key with given name. +func (s *Section) HasKey(name string) bool { + key, _ := s.GetKey(name) + return key != nil +} + +// Deprecated: Use "HasKey" instead. +func (s *Section) Haskey(name string) bool { + return s.HasKey(name) +} + +// HasValue returns true if section contains given raw value. +func (s *Section) HasValue(value string) bool { + if s.f.BlockMode { + s.f.lock.RLock() + defer s.f.lock.RUnlock() + } + + for _, k := range s.keys { + if value == k.value { + return true + } + } + return false +} + +// Key assumes named Key exists in section and returns a zero-value when not. +func (s *Section) Key(name string) *Key { + key, err := s.GetKey(name) + if err != nil { + // It's OK here because the only possible error is empty key name, + // but if it's empty, this piece of code won't be executed. + key, _ = s.NewKey(name, "") + return key + } + return key +} + +// Keys returns list of keys of section. +func (s *Section) Keys() []*Key { + keys := make([]*Key, len(s.keyList)) + for i := range s.keyList { + keys[i] = s.Key(s.keyList[i]) + } + return keys +} + +// ParentKeys returns list of keys of parent section. +func (s *Section) ParentKeys() []*Key { + var parentKeys []*Key + sname := s.name + for { + if i := strings.LastIndex(sname, "."); i > -1 { + sname = sname[:i] + sec, err := s.f.GetSection(sname) + if err != nil { + continue + } + parentKeys = append(parentKeys, sec.Keys()...) + } else { + break + } + + } + return parentKeys +} + +// KeyStrings returns list of key names of section. +func (s *Section) KeyStrings() []string { + list := make([]string, len(s.keyList)) + copy(list, s.keyList) + return list +} + +// KeysHash returns keys hash consisting of names and values. +func (s *Section) KeysHash() map[string]string { + if s.f.BlockMode { + s.f.lock.RLock() + defer s.f.lock.RUnlock() + } + + hash := map[string]string{} + for key, value := range s.keysHash { + hash[key] = value + } + return hash +} + +// DeleteKey deletes a key from section. +func (s *Section) DeleteKey(name string) { + if s.f.BlockMode { + s.f.lock.Lock() + defer s.f.lock.Unlock() + } + + for i, k := range s.keyList { + if k == name { + s.keyList = append(s.keyList[:i], s.keyList[i+1:]...) + delete(s.keys, name) + delete(s.keysHash, name) + return + } + } +} + +// ChildSections returns a list of child sections of current section. +// For example, "[parent.child1]" and "[parent.child12]" are child sections +// of section "[parent]". +func (s *Section) ChildSections() []*Section { + prefix := s.name + "." + children := make([]*Section, 0, 3) + for _, name := range s.f.sectionList { + if strings.HasPrefix(name, prefix) { + children = append(children, s.f.sections[name]...) + } + } + return children +} diff --git a/vendor/github.com/go-ini/ini/struct.go b/vendor/github.com/go-ini/ini/struct.go new file mode 100644 index 0000000000000..1df54719041a4 --- /dev/null +++ b/vendor/github.com/go-ini/ini/struct.go @@ -0,0 +1,724 @@ +// Copyright 2014 Unknwon +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +package ini + +import ( + "bytes" + "errors" + "fmt" + "reflect" + "strings" + "time" + "unicode" +) + +// NameMapper represents a ini tag name mapper. +type NameMapper func(string) string + +// Built-in name getters. +var ( + // SnackCase converts to format SNACK_CASE. + SnackCase NameMapper = func(raw string) string { + newstr := make([]rune, 0, len(raw)) + for i, chr := range raw { + if isUpper := 'A' <= chr && chr <= 'Z'; isUpper { + if i > 0 { + newstr = append(newstr, '_') + } + } + newstr = append(newstr, unicode.ToUpper(chr)) + } + return string(newstr) + } + // TitleUnderscore converts to format title_underscore. + TitleUnderscore NameMapper = func(raw string) string { + newstr := make([]rune, 0, len(raw)) + for i, chr := range raw { + if isUpper := 'A' <= chr && chr <= 'Z'; isUpper { + if i > 0 { + newstr = append(newstr, '_') + } + chr -= 'A' - 'a' + } + newstr = append(newstr, chr) + } + return string(newstr) + } +) + +func (s *Section) parseFieldName(raw, actual string) string { + if len(actual) > 0 { + return actual + } + if s.f.NameMapper != nil { + return s.f.NameMapper(raw) + } + return raw +} + +func parseDelim(actual string) string { + if len(actual) > 0 { + return actual + } + return "," +} + +var reflectTime = reflect.TypeOf(time.Now()).Kind() + +// setSliceWithProperType sets proper values to slice based on its type. +func setSliceWithProperType(key *Key, field reflect.Value, delim string, allowShadow, isStrict bool) error { + var strs []string + if allowShadow { + strs = key.StringsWithShadows(delim) + } else { + strs = key.Strings(delim) + } + + numVals := len(strs) + if numVals == 0 { + return nil + } + + var vals interface{} + var err error + + sliceOf := field.Type().Elem().Kind() + switch sliceOf { + case reflect.String: + vals = strs + case reflect.Int: + vals, err = key.parseInts(strs, true, false) + case reflect.Int64: + vals, err = key.parseInt64s(strs, true, false) + case reflect.Uint: + vals, err = key.parseUints(strs, true, false) + case reflect.Uint64: + vals, err = key.parseUint64s(strs, true, false) + case reflect.Float64: + vals, err = key.parseFloat64s(strs, true, false) + case reflect.Bool: + vals, err = key.parseBools(strs, true, false) + case reflectTime: + vals, err = key.parseTimesFormat(time.RFC3339, strs, true, false) + default: + return fmt.Errorf("unsupported type '[]%s'", sliceOf) + } + if err != nil && isStrict { + return err + } + + slice := reflect.MakeSlice(field.Type(), numVals, numVals) + for i := 0; i < numVals; i++ { + switch sliceOf { + case reflect.String: + slice.Index(i).Set(reflect.ValueOf(vals.([]string)[i])) + case reflect.Int: + slice.Index(i).Set(reflect.ValueOf(vals.([]int)[i])) + case reflect.Int64: + slice.Index(i).Set(reflect.ValueOf(vals.([]int64)[i])) + case reflect.Uint: + slice.Index(i).Set(reflect.ValueOf(vals.([]uint)[i])) + case reflect.Uint64: + slice.Index(i).Set(reflect.ValueOf(vals.([]uint64)[i])) + case reflect.Float64: + slice.Index(i).Set(reflect.ValueOf(vals.([]float64)[i])) + case reflect.Bool: + slice.Index(i).Set(reflect.ValueOf(vals.([]bool)[i])) + case reflectTime: + slice.Index(i).Set(reflect.ValueOf(vals.([]time.Time)[i])) + } + } + field.Set(slice) + return nil +} + +func wrapStrictError(err error, isStrict bool) error { + if isStrict { + return err + } + return nil +} + +// setWithProperType sets proper value to field based on its type, +// but it does not return error for failing parsing, +// because we want to use default value that is already assigned to struct. +func setWithProperType(t reflect.Type, key *Key, field reflect.Value, delim string, allowShadow, isStrict bool) error { + vt := t + isPtr := t.Kind() == reflect.Ptr + if isPtr { + vt = t.Elem() + } + switch vt.Kind() { + case reflect.String: + stringVal := key.String() + if isPtr { + field.Set(reflect.ValueOf(&stringVal)) + } else if len(stringVal) > 0 { + field.SetString(key.String()) + } + case reflect.Bool: + boolVal, err := key.Bool() + if err != nil { + return wrapStrictError(err, isStrict) + } + if isPtr { + field.Set(reflect.ValueOf(&boolVal)) + } else { + field.SetBool(boolVal) + } + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + // ParseDuration will not return err for `0`, so check the type name + if vt.Name() == "Duration" { + durationVal, err := key.Duration() + if err != nil { + if intVal, err := key.Int64(); err == nil { + field.SetInt(intVal) + return nil + } + return wrapStrictError(err, isStrict) + } + if isPtr { + field.Set(reflect.ValueOf(&durationVal)) + } else if int64(durationVal) > 0 { + field.Set(reflect.ValueOf(durationVal)) + } + return nil + } + + intVal, err := key.Int64() + if err != nil { + return wrapStrictError(err, isStrict) + } + if isPtr { + pv := reflect.New(t.Elem()) + pv.Elem().SetInt(intVal) + field.Set(pv) + } else { + field.SetInt(intVal) + } + // byte is an alias for uint8, so supporting uint8 breaks support for byte + case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64: + durationVal, err := key.Duration() + // Skip zero value + if err == nil && uint64(durationVal) > 0 { + if isPtr { + field.Set(reflect.ValueOf(&durationVal)) + } else { + field.Set(reflect.ValueOf(durationVal)) + } + return nil + } + + uintVal, err := key.Uint64() + if err != nil { + return wrapStrictError(err, isStrict) + } + if isPtr { + pv := reflect.New(t.Elem()) + pv.Elem().SetUint(uintVal) + field.Set(pv) + } else { + field.SetUint(uintVal) + } + + case reflect.Float32, reflect.Float64: + floatVal, err := key.Float64() + if err != nil { + return wrapStrictError(err, isStrict) + } + if isPtr { + pv := reflect.New(t.Elem()) + pv.Elem().SetFloat(floatVal) + field.Set(pv) + } else { + field.SetFloat(floatVal) + } + case reflectTime: + timeVal, err := key.Time() + if err != nil { + return wrapStrictError(err, isStrict) + } + if isPtr { + field.Set(reflect.ValueOf(&timeVal)) + } else { + field.Set(reflect.ValueOf(timeVal)) + } + case reflect.Slice: + return setSliceWithProperType(key, field, delim, allowShadow, isStrict) + default: + return fmt.Errorf("unsupported type %q", t) + } + return nil +} + +func parseTagOptions(tag string) (rawName string, omitEmpty bool, allowShadow bool, allowNonUnique bool) { + opts := strings.SplitN(tag, ",", 4) + rawName = opts[0] + if len(opts) > 1 { + omitEmpty = opts[1] == "omitempty" + } + if len(opts) > 2 { + allowShadow = opts[2] == "allowshadow" + } + if len(opts) > 3 { + allowNonUnique = opts[3] == "nonunique" + } + return rawName, omitEmpty, allowShadow, allowNonUnique +} + +func (s *Section) mapToField(val reflect.Value, isStrict bool) error { + if val.Kind() == reflect.Ptr { + val = val.Elem() + } + typ := val.Type() + + for i := 0; i < typ.NumField(); i++ { + field := val.Field(i) + tpField := typ.Field(i) + + tag := tpField.Tag.Get("ini") + if tag == "-" { + continue + } + + rawName, _, allowShadow, allowNonUnique := parseTagOptions(tag) + fieldName := s.parseFieldName(tpField.Name, rawName) + if len(fieldName) == 0 || !field.CanSet() { + continue + } + + isStruct := tpField.Type.Kind() == reflect.Struct + isStructPtr := tpField.Type.Kind() == reflect.Ptr && tpField.Type.Elem().Kind() == reflect.Struct + isAnonymous := tpField.Type.Kind() == reflect.Ptr && tpField.Anonymous + if isAnonymous { + field.Set(reflect.New(tpField.Type.Elem())) + } + + if isAnonymous || isStruct || isStructPtr { + if sec, err := s.f.GetSection(fieldName); err == nil { + // Only set the field to non-nil struct value if we have a section for it. + // Otherwise, we end up with a non-nil struct ptr even though there is no data. + if isStructPtr && field.IsNil() { + field.Set(reflect.New(tpField.Type.Elem())) + } + if err = sec.mapToField(field, isStrict); err != nil { + return fmt.Errorf("map to field %q: %v", fieldName, err) + } + continue + } + } + + // Map non-unique sections + if allowNonUnique && tpField.Type.Kind() == reflect.Slice { + newField, err := s.mapToSlice(fieldName, field, isStrict) + if err != nil { + return fmt.Errorf("map to slice %q: %v", fieldName, err) + } + + field.Set(newField) + continue + } + + if key, err := s.GetKey(fieldName); err == nil { + delim := parseDelim(tpField.Tag.Get("delim")) + if err = setWithProperType(tpField.Type, key, field, delim, allowShadow, isStrict); err != nil { + return fmt.Errorf("set field %q: %v", fieldName, err) + } + } + } + return nil +} + +// mapToSlice maps all sections with the same name and returns the new value. +// The type of the Value must be a slice. +func (s *Section) mapToSlice(secName string, val reflect.Value, isStrict bool) (reflect.Value, error) { + secs, err := s.f.SectionsByName(secName) + if err != nil { + return reflect.Value{}, err + } + + typ := val.Type().Elem() + for _, sec := range secs { + elem := reflect.New(typ) + if err = sec.mapToField(elem, isStrict); err != nil { + return reflect.Value{}, fmt.Errorf("map to field from section %q: %v", secName, err) + } + + val = reflect.Append(val, elem.Elem()) + } + return val, nil +} + +// mapTo maps a section to object v. +func (s *Section) mapTo(v interface{}, isStrict bool) error { + typ := reflect.TypeOf(v) + val := reflect.ValueOf(v) + if typ.Kind() == reflect.Ptr { + typ = typ.Elem() + val = val.Elem() + } else { + return errors.New("not a pointer to a struct") + } + + if typ.Kind() == reflect.Slice { + newField, err := s.mapToSlice(s.name, val, isStrict) + if err != nil { + return err + } + + val.Set(newField) + return nil + } + + return s.mapToField(val, isStrict) +} + +// MapTo maps section to given struct. +func (s *Section) MapTo(v interface{}) error { + return s.mapTo(v, false) +} + +// StrictMapTo maps section to given struct in strict mode, +// which returns all possible error including value parsing error. +func (s *Section) StrictMapTo(v interface{}) error { + return s.mapTo(v, true) +} + +// MapTo maps file to given struct. +func (f *File) MapTo(v interface{}) error { + return f.Section("").MapTo(v) +} + +// StrictMapTo maps file to given struct in strict mode, +// which returns all possible error including value parsing error. +func (f *File) StrictMapTo(v interface{}) error { + return f.Section("").StrictMapTo(v) +} + +// MapToWithMapper maps data sources to given struct with name mapper. +func MapToWithMapper(v interface{}, mapper NameMapper, source interface{}, others ...interface{}) error { + cfg, err := Load(source, others...) + if err != nil { + return err + } + cfg.NameMapper = mapper + return cfg.MapTo(v) +} + +// StrictMapToWithMapper maps data sources to given struct with name mapper in strict mode, +// which returns all possible error including value parsing error. +func StrictMapToWithMapper(v interface{}, mapper NameMapper, source interface{}, others ...interface{}) error { + cfg, err := Load(source, others...) + if err != nil { + return err + } + cfg.NameMapper = mapper + return cfg.StrictMapTo(v) +} + +// MapTo maps data sources to given struct. +func MapTo(v, source interface{}, others ...interface{}) error { + return MapToWithMapper(v, nil, source, others...) +} + +// StrictMapTo maps data sources to given struct in strict mode, +// which returns all possible error including value parsing error. +func StrictMapTo(v, source interface{}, others ...interface{}) error { + return StrictMapToWithMapper(v, nil, source, others...) +} + +// reflectSliceWithProperType does the opposite thing as setSliceWithProperType. +func reflectSliceWithProperType(key *Key, field reflect.Value, delim string, allowShadow bool) error { + slice := field.Slice(0, field.Len()) + if field.Len() == 0 { + return nil + } + sliceOf := field.Type().Elem().Kind() + + if allowShadow { + var keyWithShadows *Key + for i := 0; i < field.Len(); i++ { + var val string + switch sliceOf { + case reflect.String: + val = slice.Index(i).String() + case reflect.Int, reflect.Int64: + val = fmt.Sprint(slice.Index(i).Int()) + case reflect.Uint, reflect.Uint64: + val = fmt.Sprint(slice.Index(i).Uint()) + case reflect.Float64: + val = fmt.Sprint(slice.Index(i).Float()) + case reflect.Bool: + val = fmt.Sprint(slice.Index(i).Bool()) + case reflectTime: + val = slice.Index(i).Interface().(time.Time).Format(time.RFC3339) + default: + return fmt.Errorf("unsupported type '[]%s'", sliceOf) + } + + if i == 0 { + keyWithShadows = newKey(key.s, key.name, val) + } else { + _ = keyWithShadows.AddShadow(val) + } + } + key = keyWithShadows + return nil + } + + var buf bytes.Buffer + for i := 0; i < field.Len(); i++ { + switch sliceOf { + case reflect.String: + buf.WriteString(slice.Index(i).String()) + case reflect.Int, reflect.Int64: + buf.WriteString(fmt.Sprint(slice.Index(i).Int())) + case reflect.Uint, reflect.Uint64: + buf.WriteString(fmt.Sprint(slice.Index(i).Uint())) + case reflect.Float64: + buf.WriteString(fmt.Sprint(slice.Index(i).Float())) + case reflect.Bool: + buf.WriteString(fmt.Sprint(slice.Index(i).Bool())) + case reflectTime: + buf.WriteString(slice.Index(i).Interface().(time.Time).Format(time.RFC3339)) + default: + return fmt.Errorf("unsupported type '[]%s'", sliceOf) + } + buf.WriteString(delim) + } + key.SetValue(buf.String()[:buf.Len()-len(delim)]) + return nil +} + +// reflectWithProperType does the opposite thing as setWithProperType. +func reflectWithProperType(t reflect.Type, key *Key, field reflect.Value, delim string, allowShadow bool) error { + switch t.Kind() { + case reflect.String: + key.SetValue(field.String()) + case reflect.Bool: + key.SetValue(fmt.Sprint(field.Bool())) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + key.SetValue(fmt.Sprint(field.Int())) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + key.SetValue(fmt.Sprint(field.Uint())) + case reflect.Float32, reflect.Float64: + key.SetValue(fmt.Sprint(field.Float())) + case reflectTime: + key.SetValue(fmt.Sprint(field.Interface().(time.Time).Format(time.RFC3339))) + case reflect.Slice: + return reflectSliceWithProperType(key, field, delim, allowShadow) + case reflect.Ptr: + if !field.IsNil() { + return reflectWithProperType(t.Elem(), key, field.Elem(), delim, allowShadow) + } + default: + return fmt.Errorf("unsupported type %q", t) + } + return nil +} + +// CR: copied from encoding/json/encode.go with modifications of time.Time support. +// TODO: add more test coverage. +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 reflectTime: + t, ok := v.Interface().(time.Time) + return ok && t.IsZero() + } + return false +} + +// StructReflector is the interface implemented by struct types that can extract themselves into INI objects. +type StructReflector interface { + ReflectINIStruct(*File) error +} + +func (s *Section) reflectFrom(val reflect.Value) error { + if val.Kind() == reflect.Ptr { + val = val.Elem() + } + typ := val.Type() + + for i := 0; i < typ.NumField(); i++ { + if !val.Field(i).CanInterface() { + continue + } + + field := val.Field(i) + tpField := typ.Field(i) + + tag := tpField.Tag.Get("ini") + if tag == "-" { + continue + } + + rawName, omitEmpty, allowShadow, allowNonUnique := parseTagOptions(tag) + if omitEmpty && isEmptyValue(field) { + continue + } + + if r, ok := field.Interface().(StructReflector); ok { + return r.ReflectINIStruct(s.f) + } + + fieldName := s.parseFieldName(tpField.Name, rawName) + if len(fieldName) == 0 || !field.CanSet() { + continue + } + + if (tpField.Type.Kind() == reflect.Ptr && tpField.Anonymous) || + (tpField.Type.Kind() == reflect.Struct && tpField.Type.Name() != "Time") { + // Note: The only error here is section doesn't exist. + sec, err := s.f.GetSection(fieldName) + if err != nil { + // Note: fieldName can never be empty here, ignore error. + sec, _ = s.f.NewSection(fieldName) + } + + // Add comment from comment tag + if len(sec.Comment) == 0 { + sec.Comment = tpField.Tag.Get("comment") + } + + if err = sec.reflectFrom(field); err != nil { + return fmt.Errorf("reflect from field %q: %v", fieldName, err) + } + continue + } + + if allowNonUnique && tpField.Type.Kind() == reflect.Slice { + slice := field.Slice(0, field.Len()) + if field.Len() == 0 { + return nil + } + sliceOf := field.Type().Elem().Kind() + + for i := 0; i < field.Len(); i++ { + if sliceOf != reflect.Struct && sliceOf != reflect.Ptr { + return fmt.Errorf("field %q is not a slice of pointer or struct", fieldName) + } + + sec, err := s.f.NewSection(fieldName) + if err != nil { + return err + } + + // Add comment from comment tag + if len(sec.Comment) == 0 { + sec.Comment = tpField.Tag.Get("comment") + } + + if err := sec.reflectFrom(slice.Index(i)); err != nil { + return fmt.Errorf("reflect from field %q: %v", fieldName, err) + } + } + continue + } + + // Note: Same reason as section. + key, err := s.GetKey(fieldName) + if err != nil { + key, _ = s.NewKey(fieldName, "") + } + + // Add comment from comment tag + if len(key.Comment) == 0 { + key.Comment = tpField.Tag.Get("comment") + } + + delim := parseDelim(tpField.Tag.Get("delim")) + if err = reflectWithProperType(tpField.Type, key, field, delim, allowShadow); err != nil { + return fmt.Errorf("reflect field %q: %v", fieldName, err) + } + + } + return nil +} + +// ReflectFrom reflects section from given struct. It overwrites existing ones. +func (s *Section) ReflectFrom(v interface{}) error { + typ := reflect.TypeOf(v) + val := reflect.ValueOf(v) + + if s.name != DefaultSection && s.f.options.AllowNonUniqueSections && + (typ.Kind() == reflect.Slice || typ.Kind() == reflect.Ptr) { + // Clear sections to make sure none exists before adding the new ones + s.f.DeleteSection(s.name) + + if typ.Kind() == reflect.Ptr { + sec, err := s.f.NewSection(s.name) + if err != nil { + return err + } + return sec.reflectFrom(val.Elem()) + } + + slice := val.Slice(0, val.Len()) + sliceOf := val.Type().Elem().Kind() + if sliceOf != reflect.Ptr { + return fmt.Errorf("not a slice of pointers") + } + + for i := 0; i < slice.Len(); i++ { + sec, err := s.f.NewSection(s.name) + if err != nil { + return err + } + + err = sec.reflectFrom(slice.Index(i)) + if err != nil { + return fmt.Errorf("reflect from %dth field: %v", i, err) + } + } + + return nil + } + + if typ.Kind() == reflect.Ptr { + val = val.Elem() + } else { + return errors.New("not a pointer to a struct") + } + + return s.reflectFrom(val) +} + +// ReflectFrom reflects file from given struct. +func (f *File) ReflectFrom(v interface{}) error { + return f.Section("").ReflectFrom(v) +} + +// ReflectFromWithMapper reflects data sources from given struct with name mapper. +func ReflectFromWithMapper(cfg *File, v interface{}, mapper NameMapper) error { + cfg.NameMapper = mapper + return cfg.ReflectFrom(v) +} + +// ReflectFrom reflects data sources from given struct. +func ReflectFrom(cfg *File, v interface{}) error { + return ReflectFromWithMapper(cfg, v, nil) +} diff --git a/vendor/github.com/minio/minio-go/.gitignore b/vendor/github.com/minio/minio-go/.gitignore new file mode 100644 index 0000000000000..fa967abd77014 --- /dev/null +++ b/vendor/github.com/minio/minio-go/.gitignore @@ -0,0 +1,3 @@ +*~ +*.test +validator diff --git a/vendor/github.com/minio/minio-go/.travis.yml b/vendor/github.com/minio/minio-go/.travis.yml new file mode 100644 index 0000000000000..7ed7df14e792e --- /dev/null +++ b/vendor/github.com/minio/minio-go/.travis.yml @@ -0,0 +1,28 @@ +sudo: false +language: go + +os: +- linux + +env: +- ARCH=x86_64 +- ARCH=i686 + +go: +- 1.11.x +- tip + +matrix: + fast_finish: true + allow_failures: + - go: tip + +addons: + apt: + packages: + - devscripts + +script: +- diff -au <(gofmt -d .) <(printf "") +- diff -au <(licensecheck --check '.go$' --recursive --lines 0 * | grep -v -w 'Apache (v2.0)') <(printf "") +- make diff --git a/vendor/github.com/minio/minio-go/CONTRIBUTING.md b/vendor/github.com/minio/minio-go/CONTRIBUTING.md new file mode 100644 index 0000000000000..8b1ee86c6d098 --- /dev/null +++ b/vendor/github.com/minio/minio-go/CONTRIBUTING.md @@ -0,0 +1,23 @@ + +### Developer Guidelines + +``minio-go`` welcomes your contribution. To make the process as seamless as possible, we ask for the following: + +* Go ahead and fork the project and make your changes. We encourage pull requests to discuss code changes. + - Fork it + - Create your feature branch (git checkout -b my-new-feature) + - Commit your changes (git commit -am 'Add some feature') + - Push to the branch (git push origin my-new-feature) + - Create new Pull Request + +* When you're ready to create a pull request, be sure to: + - Have test cases for the new code. If you have questions about how to do it, please ask in your pull request. + - Run `go fmt` + - Squash your commits into a single commit. `git rebase -i`. It's okay to force update your pull request. + - Make sure `go test -race ./...` and `go build` completes. + NOTE: go test runs functional tests and requires you to have a AWS S3 account. Set them as environment variables + ``ACCESS_KEY`` and ``SECRET_KEY``. To run shorter version of the tests please use ``go test -short -race ./...`` + +* Read [Effective Go](https://github.com/golang/go/wiki/CodeReviewComments) article from Golang project + - `minio-go` project is strictly conformant with Golang style + - if you happen to observe offending code, please feel free to send a pull request diff --git a/vendor/github.com/minio/minio-go/LICENSE b/vendor/github.com/minio/minio-go/LICENSE new file mode 100644 index 0000000000000..d645695673349 --- /dev/null +++ b/vendor/github.com/minio/minio-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/github.com/minio/minio-go/MAINTAINERS.md b/vendor/github.com/minio/minio-go/MAINTAINERS.md new file mode 100644 index 0000000000000..17973078eaae7 --- /dev/null +++ b/vendor/github.com/minio/minio-go/MAINTAINERS.md @@ -0,0 +1,35 @@ +# For maintainers only + +## Responsibilities + +Please go through this link [Maintainer Responsibility](https://gist.github.com/abperiasamy/f4d9b31d3186bbd26522) + +### Making new releases +Tag and sign your release commit, additionally this step requires you to have access to Minio's trusted private key. +```sh +$ export GNUPGHOME=/media/${USER}/minio/trusted +$ git tag -s 4.0.0 +$ git push +$ git push --tags +``` + +### Update version +Once release has been made update `libraryVersion` constant in `api.go` to next to be released version. + +```sh +$ grep libraryVersion api.go + libraryVersion = "4.0.1" +``` + +Commit your changes +``` +$ git commit -a -m "Update version for next release" --author "Minio Trusted " +``` + +### Announce +Announce new release by adding release notes at https://github.com/minio/minio-go/releases from `trusted@minio.io` account. Release notes requires two sections `highlights` and `changelog`. Highlights is a bulleted list of salient features in this release and Changelog contains list of all commits since the last release. + +To generate `changelog` +```sh +$ git log --no-color --pretty=format:'-%d %s (%cr) <%an>' .. +``` diff --git a/vendor/github.com/minio/minio-go/Makefile b/vendor/github.com/minio/minio-go/Makefile new file mode 100644 index 0000000000000..bad81ffaf8a9e --- /dev/null +++ b/vendor/github.com/minio/minio-go/Makefile @@ -0,0 +1,15 @@ +all: checks + +checks: + @go get -t ./... + @go vet ./... + @SERVER_ENDPOINT=play.minio.io:9000 ACCESS_KEY=Q3AM3UQ867SPQQA43P2F SECRET_KEY=zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG ENABLE_HTTPS=1 MINT_MODE=full go test -race -v ./... + @go get github.com/dustin/go-humanize/... + @go get github.com/sirupsen/logrus/... + @SERVER_ENDPOINT=play.minio.io:9000 ACCESS_KEY=Q3AM3UQ867SPQQA43P2F SECRET_KEY=zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG ENABLE_HTTPS=1 MINT_MODE=full go run functional_tests.go + @mkdir -p /tmp/examples && for i in $(echo examples/s3/*); do go build -o /tmp/examples/$(basename ${i:0:-3}) ${i}; done + @go get -u github.com/a8m/mark/... + @go get -u github.com/minio/cli/... + @go get -u golang.org/x/tools/cmd/goimports + @go get -u github.com/gernest/wow/... + @go build docs/validator.go && ./validator -m docs/API.md -t docs/checker.go.tpl diff --git a/vendor/github.com/minio/minio-go/NOTICE b/vendor/github.com/minio/minio-go/NOTICE new file mode 100644 index 0000000000000..c521791c5bf38 --- /dev/null +++ b/vendor/github.com/minio/minio-go/NOTICE @@ -0,0 +1,2 @@ +minio-go +Copyright 2015-2017 Minio, Inc. \ No newline at end of file diff --git a/vendor/github.com/minio/minio-go/README.md b/vendor/github.com/minio/minio-go/README.md new file mode 100644 index 0000000000000..ad9d5e60bedf3 --- /dev/null +++ b/vendor/github.com/minio/minio-go/README.md @@ -0,0 +1,239 @@ +# Minio Go Client SDK for Amazon S3 Compatible Cloud Storage [![Slack](https://slack.minio.io/slack?type=svg)](https://slack.minio.io) [![Sourcegraph](https://sourcegraph.com/github.com/minio/minio-go/-/badge.svg)](https://sourcegraph.com/github.com/minio/minio-go?badge) [![Apache V2 License](http://img.shields.io/badge/license-Apache%20V2-blue.svg)](https://github.com/minio/minio-go/blob/master/LICENSE) + +The Minio Go Client SDK provides simple APIs to access any Amazon S3 compatible object storage. + +This quickstart guide will show you how to install the Minio client SDK, connect to Minio, and provide a walkthrough for a simple file uploader. For a complete list of APIs and examples, please take a look at the [Go Client API Reference](https://docs.minio.io/docs/golang-client-api-reference). + +This document assumes that you have a working [Go development environment](https://docs.minio.io/docs/how-to-install-golang). + +## Download from Github +```sh +go get -u github.com/minio/minio-go +``` + +## Initialize Minio Client +Minio client requires the following four parameters specified to connect to an Amazon S3 compatible object storage. + +| Parameter | Description| +| :--- | :--- | +| endpoint | URL to object storage service. | +| accessKeyID | Access key is the user ID that uniquely identifies your account. | +| secretAccessKey | Secret key is the password to your account. | +| secure | Set this value to 'true' to enable secure (HTTPS) access. | + + +```go +package main + +import ( + "github.com/minio/minio-go" + "log" +) + +func main() { + endpoint := "play.minio.io:9000" + accessKeyID := "Q3AM3UQ867SPQQA43P2F" + secretAccessKey := "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG" + useSSL := true + + // Initialize minio client object. + minioClient, err := minio.New(endpoint, accessKeyID, secretAccessKey, useSSL) + if err != nil { + log.Fatalln(err) + } + + log.Printf("%#v\n", minioClient) // minioClient is now setup +} +``` + +## Quick Start Example - File Uploader +This example program connects to an object storage server, creates a bucket and uploads a file to the bucket. + +We will use the Minio server running at [https://play.minio.io:9000](https://play.minio.io:9000) in this example. Feel free to use this service for testing and development. Access credentials shown in this example are open to the public. + +### FileUploader.go +```go +package main + +import ( + "github.com/minio/minio-go" + "log" +) + +func main() { + endpoint := "play.minio.io:9000" + accessKeyID := "Q3AM3UQ867SPQQA43P2F" + secretAccessKey := "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG" + useSSL := true + + // Initialize minio client object. + minioClient, err := minio.New(endpoint, accessKeyID, secretAccessKey, useSSL) + if err != nil { + log.Fatalln(err) + } + + // Make a new bucket called mymusic. + bucketName := "mymusic" + location := "us-east-1" + + err = minioClient.MakeBucket(bucketName, location) + if err != nil { + // Check to see if we already own this bucket (which happens if you run this twice) + exists, err := minioClient.BucketExists(bucketName) + if err == nil && exists { + log.Printf("We already own %s\n", bucketName) + } else { + log.Fatalln(err) + } + } else { + log.Printf("Successfully created %s\n", bucketName) + } + + // Upload the zip file + objectName := "golden-oldies.zip" + filePath := "/tmp/golden-oldies.zip" + contentType := "application/zip" + + // Upload the zip file with FPutObject + n, err := minioClient.FPutObject(bucketName, objectName, filePath, minio.PutObjectOptions{ContentType:contentType}) + if err != nil { + log.Fatalln(err) + } + + log.Printf("Successfully uploaded %s of size %d\n", objectName, n) +} +``` + +### Run FileUploader +```sh +go run file-uploader.go +2016/08/13 17:03:28 Successfully created mymusic +2016/08/13 17:03:40 Successfully uploaded golden-oldies.zip of size 16253413 + +mc ls play/mymusic/ +[2016-05-27 16:02:16 PDT] 17MiB golden-oldies.zip +``` + +## API Reference +The full API Reference is available here. + +* [Complete API Reference](https://docs.minio.io/docs/golang-client-api-reference) + +### API Reference : Bucket Operations +* [`MakeBucket`](https://docs.minio.io/docs/golang-client-api-reference#MakeBucket) +* [`ListBuckets`](https://docs.minio.io/docs/golang-client-api-reference#ListBuckets) +* [`BucketExists`](https://docs.minio.io/docs/golang-client-api-reference#BucketExists) +* [`RemoveBucket`](https://docs.minio.io/docs/golang-client-api-reference#RemoveBucket) +* [`ListObjects`](https://docs.minio.io/docs/golang-client-api-reference#ListObjects) +* [`ListObjectsV2`](https://docs.minio.io/docs/golang-client-api-reference#ListObjectsV2) +* [`ListIncompleteUploads`](https://docs.minio.io/docs/golang-client-api-reference#ListIncompleteUploads) + +### API Reference : Bucket policy Operations +* [`SetBucketPolicy`](https://docs.minio.io/docs/golang-client-api-reference#SetBucketPolicy) +* [`GetBucketPolicy`](https://docs.minio.io/docs/golang-client-api-reference#GetBucketPolicy) + +### API Reference : Bucket notification Operations +* [`SetBucketNotification`](https://docs.minio.io/docs/golang-client-api-reference#SetBucketNotification) +* [`GetBucketNotification`](https://docs.minio.io/docs/golang-client-api-reference#GetBucketNotification) +* [`RemoveAllBucketNotification`](https://docs.minio.io/docs/golang-client-api-reference#RemoveAllBucketNotification) +* [`ListenBucketNotification`](https://docs.minio.io/docs/golang-client-api-reference#ListenBucketNotification) (Minio Extension) + +### API Reference : File Object Operations +* [`FPutObject`](https://docs.minio.io/docs/golang-client-api-reference#FPutObject) +* [`FGetObject`](https://docs.minio.io/docs/golang-client-api-reference#FGetObject) +* [`FPutObjectWithContext`](https://docs.minio.io/docs/golang-client-api-reference#FPutObjectWithContext) +* [`FGetObjectWithContext`](https://docs.minio.io/docs/golang-client-api-reference#FGetObjectWithContext) + +### API Reference : Object Operations +* [`GetObject`](https://docs.minio.io/docs/golang-client-api-reference#GetObject) +* [`PutObject`](https://docs.minio.io/docs/golang-client-api-reference#PutObject) +* [`GetObjectWithContext`](https://docs.minio.io/docs/golang-client-api-reference#GetObjectWithContext) +* [`PutObjectWithContext`](https://docs.minio.io/docs/golang-client-api-reference#PutObjectWithContext) +* [`PutObjectStreaming`](https://docs.minio.io/docs/golang-client-api-reference#PutObjectStreaming) +* [`StatObject`](https://docs.minio.io/docs/golang-client-api-reference#StatObject) +* [`CopyObject`](https://docs.minio.io/docs/golang-client-api-reference#CopyObject) +* [`RemoveObject`](https://docs.minio.io/docs/golang-client-api-reference#RemoveObject) +* [`RemoveObjects`](https://docs.minio.io/docs/golang-client-api-reference#RemoveObjects) +* [`RemoveIncompleteUpload`](https://docs.minio.io/docs/golang-client-api-reference#RemoveIncompleteUpload) +* [`SelectObjectContent`](https://docs.minio.io/docs/golang-client-api-reference#SelectObjectContent) + + +### API Reference : Presigned Operations +* [`PresignedGetObject`](https://docs.minio.io/docs/golang-client-api-reference#PresignedGetObject) +* [`PresignedPutObject`](https://docs.minio.io/docs/golang-client-api-reference#PresignedPutObject) +* [`PresignedHeadObject`](https://docs.minio.io/docs/golang-client-api-reference#PresignedHeadObject) +* [`PresignedPostPolicy`](https://docs.minio.io/docs/golang-client-api-reference#PresignedPostPolicy) + +### API Reference : Client custom settings +* [`SetAppInfo`](http://docs.minio.io/docs/golang-client-api-reference#SetAppInfo) +* [`SetCustomTransport`](http://docs.minio.io/docs/golang-client-api-reference#SetCustomTransport) +* [`TraceOn`](http://docs.minio.io/docs/golang-client-api-reference#TraceOn) +* [`TraceOff`](http://docs.minio.io/docs/golang-client-api-reference#TraceOff) + +## Full Examples + +### Full Examples : Bucket Operations +* [makebucket.go](https://github.com/minio/minio-go/blob/master/examples/s3/makebucket.go) +* [listbuckets.go](https://github.com/minio/minio-go/blob/master/examples/s3/listbuckets.go) +* [bucketexists.go](https://github.com/minio/minio-go/blob/master/examples/s3/bucketexists.go) +* [removebucket.go](https://github.com/minio/minio-go/blob/master/examples/s3/removebucket.go) +* [listobjects.go](https://github.com/minio/minio-go/blob/master/examples/s3/listobjects.go) +* [listobjectsV2.go](https://github.com/minio/minio-go/blob/master/examples/s3/listobjectsV2.go) +* [listincompleteuploads.go](https://github.com/minio/minio-go/blob/master/examples/s3/listincompleteuploads.go) + +### Full Examples : Bucket policy Operations +* [setbucketpolicy.go](https://github.com/minio/minio-go/blob/master/examples/s3/setbucketpolicy.go) +* [getbucketpolicy.go](https://github.com/minio/minio-go/blob/master/examples/s3/getbucketpolicy.go) +* [listbucketpolicies.go](https://github.com/minio/minio-go/blob/master/examples/s3/listbucketpolicies.go) + +### Full Examples : Bucket lifecycle Operations +* [setbucketlifecycle.go](https://github.com/minio/minio-go/blob/master/examples/s3/setbucketlifecycle.go) +* [getbucketlifecycle.go](https://github.com/minio/minio-go/blob/master/examples/s3/getbucketlifecycle.go) + +### Full Examples : Bucket notification Operations +* [setbucketnotification.go](https://github.com/minio/minio-go/blob/master/examples/s3/setbucketnotification.go) +* [getbucketnotification.go](https://github.com/minio/minio-go/blob/master/examples/s3/getbucketnotification.go) +* [removeallbucketnotification.go](https://github.com/minio/minio-go/blob/master/examples/s3/removeallbucketnotification.go) +* [listenbucketnotification.go](https://github.com/minio/minio-go/blob/master/examples/minio/listenbucketnotification.go) (Minio Extension) + +### Full Examples : File Object Operations +* [fputobject.go](https://github.com/minio/minio-go/blob/master/examples/s3/fputobject.go) +* [fgetobject.go](https://github.com/minio/minio-go/blob/master/examples/s3/fgetobject.go) +* [fputobject-context.go](https://github.com/minio/minio-go/blob/master/examples/s3/fputobject-context.go) +* [fgetobject-context.go](https://github.com/minio/minio-go/blob/master/examples/s3/fgetobject-context.go) + +### Full Examples : Object Operations +* [putobject.go](https://github.com/minio/minio-go/blob/master/examples/s3/putobject.go) +* [getobject.go](https://github.com/minio/minio-go/blob/master/examples/s3/getobject.go) +* [putobject-context.go](https://github.com/minio/minio-go/blob/master/examples/s3/putobject-context.go) +* [getobject-context.go](https://github.com/minio/minio-go/blob/master/examples/s3/getobject-context.go) +* [statobject.go](https://github.com/minio/minio-go/blob/master/examples/s3/statobject.go) +* [copyobject.go](https://github.com/minio/minio-go/blob/master/examples/s3/copyobject.go) +* [removeobject.go](https://github.com/minio/minio-go/blob/master/examples/s3/removeobject.go) +* [removeincompleteupload.go](https://github.com/minio/minio-go/blob/master/examples/s3/removeincompleteupload.go) +* [removeobjects.go](https://github.com/minio/minio-go/blob/master/examples/s3/removeobjects.go) + +### Full Examples : Encrypted Object Operations +* [put-encrypted-object.go](https://github.com/minio/minio-go/blob/master/examples/s3/put-encrypted-object.go) +* [get-encrypted-object.go](https://github.com/minio/minio-go/blob/master/examples/s3/get-encrypted-object.go) +* [fput-encrypted-object.go](https://github.com/minio/minio-go/blob/master/examples/s3/fputencrypted-object.go) + +### Full Examples : Presigned Operations +* [presignedgetobject.go](https://github.com/minio/minio-go/blob/master/examples/s3/presignedgetobject.go) +* [presignedputobject.go](https://github.com/minio/minio-go/blob/master/examples/s3/presignedputobject.go) +* [presignedheadobject.go](https://github.com/minio/minio-go/blob/master/examples/s3/presignedheadobject.go) +* [presignedpostpolicy.go](https://github.com/minio/minio-go/blob/master/examples/s3/presignedpostpolicy.go) + +## Explore Further +* [Complete Documentation](https://docs.minio.io) +* [Minio Go Client SDK API Reference](https://docs.minio.io/docs/golang-client-api-reference) +* [Go Music Player App Full Application Example](https://docs.minio.io/docs/go-music-player-app) + +## Contribute +[Contributors Guide](https://github.com/minio/minio-go/blob/master/CONTRIBUTING.md) + +[![Build Status](https://travis-ci.org/minio/minio-go.svg)](https://travis-ci.org/minio/minio-go) +[![Build status](https://ci.appveyor.com/api/projects/status/1d05e6nvxcelmrak?svg=true)](https://ci.appveyor.com/project/harshavardhana/minio-go) + +## License +This SDK is distributed under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0), see [LICENSE](./LICENSE) and [NOTICE](./NOTICE) for more information. diff --git a/vendor/github.com/minio/minio-go/README_zh_CN.md b/vendor/github.com/minio/minio-go/README_zh_CN.md new file mode 100644 index 0000000000000..a5acf199e569e --- /dev/null +++ b/vendor/github.com/minio/minio-go/README_zh_CN.md @@ -0,0 +1,245 @@ +# 适用于与Amazon S3兼容云存储的Minio Go SDK [![Slack](https://slack.minio.io/slack?type=svg)](https://slack.minio.io) [![Sourcegraph](https://sourcegraph.com/github.com/minio/minio-go/-/badge.svg)](https://sourcegraph.com/github.com/minio/minio-go?badge) + +Minio Go Client SDK提供了简单的API来访问任何与Amazon S3兼容的对象存储服务。 + +**支持的云存储:** + +- AWS Signature Version 4 + - Amazon S3 + - Minio + +- AWS Signature Version 2 + - Google Cloud Storage (兼容模式) + - Openstack Swift + Swift3 middleware + - Ceph Object Gateway + - Riak CS + +本文我们将学习如何安装Minio client SDK,连接到Minio,并提供一下文件上传的示例。对于完整的API以及示例,请参考[Go Client API Reference](https://docs.minio.io/docs/golang-client-api-reference)。 + +本文假设你已经有 [Go开发环境](https://docs.minio.io/docs/how-to-install-golang)。 + +## 从Github下载 +```sh +go get -u github.com/minio/minio-go +``` + +## 初始化Minio Client +Minio client需要以下4个参数来连接与Amazon S3兼容的对象存储。 + +| 参数 | 描述| +| :--- | :--- | +| endpoint | 对象存储服务的URL | +| accessKeyID | Access key是唯一标识你的账户的用户ID。 | +| secretAccessKey | Secret key是你账户的密码。 | +| secure | true代表使用HTTPS | + + +```go +package main + +import ( + "github.com/minio/minio-go" + "log" +) + +func main() { + endpoint := "play.minio.io:9000" + accessKeyID := "Q3AM3UQ867SPQQA43P2F" + secretAccessKey := "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG" + useSSL := true + + // 初使化 minio client对象。 + minioClient, err := minio.New(endpoint, accessKeyID, secretAccessKey, useSSL) + if err != nil { + log.Fatalln(err) + } + + log.Printf("%#v\n", minioClient) // minioClient初使化成功 +} +``` + +## 示例-文件上传 +本示例连接到一个对象存储服务,创建一个存储桶并上传一个文件到存储桶中。 + +我们在本示例中使用运行在 [https://play.minio.io:9000](https://play.minio.io:9000) 上的Minio服务,你可以用这个服务来开发和测试。示例中的访问凭据是公开的。 + +### FileUploader.go +```go +package main + +import ( + "github.com/minio/minio-go" + "log" +) + +func main() { + endpoint := "play.minio.io:9000" + accessKeyID := "Q3AM3UQ867SPQQA43P2F" + secretAccessKey := "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG" + useSSL := true + + // 初使化minio client对象。 + minioClient, err := minio.New(endpoint, accessKeyID, secretAccessKey, useSSL) + if err != nil { + log.Fatalln(err) + } + + // 创建一个叫mymusic的存储桶。 + bucketName := "mymusic" + location := "us-east-1" + + err = minioClient.MakeBucket(bucketName, location) + if err != nil { + // 检查存储桶是否已经存在。 + exists, err := minioClient.BucketExists(bucketName) + if err == nil && exists { + log.Printf("We already own %s\n", bucketName) + } else { + log.Fatalln(err) + } + } + log.Printf("Successfully created %s\n", bucketName) + + // 上传一个zip文件。 + objectName := "golden-oldies.zip" + filePath := "/tmp/golden-oldies.zip" + contentType := "application/zip" + + // 使用FPutObject上传一个zip文件。 + n, err := minioClient.FPutObject(bucketName, objectName, filePath, minio.PutObjectOptions{ContentType:contentType}) + if err != nil { + log.Fatalln(err) + } + + log.Printf("Successfully uploaded %s of size %d\n", objectName, n) +} +``` + +### 运行FileUploader +```sh +go run file-uploader.go +2016/08/13 17:03:28 Successfully created mymusic +2016/08/13 17:03:40 Successfully uploaded golden-oldies.zip of size 16253413 + +mc ls play/mymusic/ +[2016-05-27 16:02:16 PDT] 17MiB golden-oldies.zip +``` + +## API文档 +完整的API文档在这里。 +* [完整API文档](https://docs.minio.io/docs/golang-client-api-reference) + +### API文档 : 操作存储桶 +* [`MakeBucket`](https://docs.minio.io/docs/golang-client-api-reference#MakeBucket) +* [`ListBuckets`](https://docs.minio.io/docs/golang-client-api-reference#ListBuckets) +* [`BucketExists`](https://docs.minio.io/docs/golang-client-api-reference#BucketExists) +* [`RemoveBucket`](https://docs.minio.io/docs/golang-client-api-reference#RemoveBucket) +* [`ListObjects`](https://docs.minio.io/docs/golang-client-api-reference#ListObjects) +* [`ListObjectsV2`](https://docs.minio.io/docs/golang-client-api-reference#ListObjectsV2) +* [`ListIncompleteUploads`](https://docs.minio.io/docs/golang-client-api-reference#ListIncompleteUploads) + +### API文档 : 存储桶策略 +* [`SetBucketPolicy`](https://docs.minio.io/docs/golang-client-api-reference#SetBucketPolicy) +* [`GetBucketPolicy`](https://docs.minio.io/docs/golang-client-api-reference#GetBucketPolicy) + +### API文档 : 存储桶通知 +* [`SetBucketNotification`](https://docs.minio.io/docs/golang-client-api-reference#SetBucketNotification) +* [`GetBucketNotification`](https://docs.minio.io/docs/golang-client-api-reference#GetBucketNotification) +* [`RemoveAllBucketNotification`](https://docs.minio.io/docs/golang-client-api-reference#RemoveAllBucketNotification) +* [`ListenBucketNotification`](https://docs.minio.io/docs/golang-client-api-reference#ListenBucketNotification) (Minio Extension) + +### API文档 : 操作文件对象 +* [`FPutObject`](https://docs.minio.io/docs/golang-client-api-reference#FPutObject) +* [`FGetObject`](https://docs.minio.io/docs/golang-client-api-reference#FPutObject) +* [`FPutObjectWithContext`](https://docs.minio.io/docs/golang-client-api-reference#FPutObjectWithContext) +* [`FGetObjectWithContext`](https://docs.minio.io/docs/golang-client-api-reference#FGetObjectWithContext) + +### API文档 : 操作对象 +* [`GetObject`](https://docs.minio.io/docs/golang-client-api-reference#GetObject) +* [`PutObject`](https://docs.minio.io/docs/golang-client-api-reference#PutObject) +* [`GetObjectWithContext`](https://docs.minio.io/docs/golang-client-api-reference#GetObjectWithContext) +* [`PutObjectWithContext`](https://docs.minio.io/docs/golang-client-api-reference#PutObjectWithContext) +* [`PutObjectStreaming`](https://docs.minio.io/docs/golang-client-api-reference#PutObjectStreaming) +* [`StatObject`](https://docs.minio.io/docs/golang-client-api-reference#StatObject) +* [`CopyObject`](https://docs.minio.io/docs/golang-client-api-reference#CopyObject) +* [`RemoveObject`](https://docs.minio.io/docs/golang-client-api-reference#RemoveObject) +* [`RemoveObjects`](https://docs.minio.io/docs/golang-client-api-reference#RemoveObjects) +* [`RemoveIncompleteUpload`](https://docs.minio.io/docs/golang-client-api-reference#RemoveIncompleteUpload) + +### API文档: 操作加密对象 +* [`GetEncryptedObject`](https://docs.minio.io/docs/golang-client-api-reference#GetEncryptedObject) +* [`PutEncryptedObject`](https://docs.minio.io/docs/golang-client-api-reference#PutEncryptedObject) + +### API文档 : Presigned操作 +* [`PresignedGetObject`](https://docs.minio.io/docs/golang-client-api-reference#PresignedGetObject) +* [`PresignedPutObject`](https://docs.minio.io/docs/golang-client-api-reference#PresignedPutObject) +* [`PresignedHeadObject`](https://docs.minio.io/docs/golang-client-api-reference#PresignedHeadObject) +* [`PresignedPostPolicy`](https://docs.minio.io/docs/golang-client-api-reference#PresignedPostPolicy) + +### API文档 : 客户端自定义设置 +* [`SetAppInfo`](http://docs.minio.io/docs/golang-client-api-reference#SetAppInfo) +* [`SetCustomTransport`](http://docs.minio.io/docs/golang-client-api-reference#SetCustomTransport) +* [`TraceOn`](http://docs.minio.io/docs/golang-client-api-reference#TraceOn) +* [`TraceOff`](http://docs.minio.io/docs/golang-client-api-reference#TraceOff) + +## 完整示例 + +### 完整示例 : 操作存储桶 +* [makebucket.go](https://github.com/minio/minio-go/blob/master/examples/s3/makebucket.go) +* [listbuckets.go](https://github.com/minio/minio-go/blob/master/examples/s3/listbuckets.go) +* [bucketexists.go](https://github.com/minio/minio-go/blob/master/examples/s3/bucketexists.go) +* [removebucket.go](https://github.com/minio/minio-go/blob/master/examples/s3/removebucket.go) +* [listobjects.go](https://github.com/minio/minio-go/blob/master/examples/s3/listobjects.go) +* [listobjectsV2.go](https://github.com/minio/minio-go/blob/master/examples/s3/listobjectsV2.go) +* [listincompleteuploads.go](https://github.com/minio/minio-go/blob/master/examples/s3/listincompleteuploads.go) + +### 完整示例 : 存储桶策略 +* [setbucketpolicy.go](https://github.com/minio/minio-go/blob/master/examples/s3/setbucketpolicy.go) +* [getbucketpolicy.go](https://github.com/minio/minio-go/blob/master/examples/s3/getbucketpolicy.go) +* [listbucketpolicies.go](https://github.com/minio/minio-go/blob/master/examples/s3/listbucketpolicies.go) + +### 完整示例 : 存储桶通知 +* [setbucketnotification.go](https://github.com/minio/minio-go/blob/master/examples/s3/setbucketnotification.go) +* [getbucketnotification.go](https://github.com/minio/minio-go/blob/master/examples/s3/getbucketnotification.go) +* [removeallbucketnotification.go](https://github.com/minio/minio-go/blob/master/examples/s3/removeallbucketnotification.go) +* [listenbucketnotification.go](https://github.com/minio/minio-go/blob/master/examples/minio/listenbucketnotification.go) (Minio扩展) + +### 完整示例 : 操作文件对象 +* [fputobject.go](https://github.com/minio/minio-go/blob/master/examples/s3/fputobject.go) +* [fgetobject.go](https://github.com/minio/minio-go/blob/master/examples/s3/fgetobject.go) +* [fputobject-context.go](https://github.com/minio/minio-go/blob/master/examples/s3/fputobject-context.go) +* [fgetobject-context.go](https://github.com/minio/minio-go/blob/master/examples/s3/fgetobject-context.go) + +### 完整示例 : 操作对象 +* [putobject.go](https://github.com/minio/minio-go/blob/master/examples/s3/putobject.go) +* [getobject.go](https://github.com/minio/minio-go/blob/master/examples/s3/getobject.go) +* [putobject-context.go](https://github.com/minio/minio-go/blob/master/examples/s3/putobject-context.go) +* [getobject-context.go](https://github.com/minio/minio-go/blob/master/examples/s3/getobject-context.go) +* [statobject.go](https://github.com/minio/minio-go/blob/master/examples/s3/statobject.go) +* [copyobject.go](https://github.com/minio/minio-go/blob/master/examples/s3/copyobject.go) +* [removeobject.go](https://github.com/minio/minio-go/blob/master/examples/s3/removeobject.go) +* [removeincompleteupload.go](https://github.com/minio/minio-go/blob/master/examples/s3/removeincompleteupload.go) +* [removeobjects.go](https://github.com/minio/minio-go/blob/master/examples/s3/removeobjects.go) + +### 完整示例 : 操作加密对象 +* [put-encrypted-object.go](https://github.com/minio/minio-go/blob/master/examples/s3/put-encrypted-object.go) +* [get-encrypted-object.go](https://github.com/minio/minio-go/blob/master/examples/s3/get-encrypted-object.go) +* [fput-encrypted-object.go](https://github.com/minio/minio-go/blob/master/examples/s3/fputencrypted-object.go) + +### 完整示例 : Presigned操作 +* [presignedgetobject.go](https://github.com/minio/minio-go/blob/master/examples/s3/presignedgetobject.go) +* [presignedputobject.go](https://github.com/minio/minio-go/blob/master/examples/s3/presignedputobject.go) +* [presignedheadobject.go](https://github.com/minio/minio-go/blob/master/examples/s3/presignedheadobject.go) +* [presignedpostpolicy.go](https://github.com/minio/minio-go/blob/master/examples/s3/presignedpostpolicy.go) + +## 了解更多 +* [完整文档](https://docs.minio.io) +* [Minio Go Client SDK API文档](https://docs.minio.io/docs/golang-client-api-reference) +* [Go 音乐播放器完整示例](https://docs.minio.io/docs/go-music-player-app) + +## 贡献 +[贡献指南](https://github.com/minio/minio-go/blob/master/docs/zh_CN/CONTRIBUTING.md) + +[![Build Status](https://travis-ci.org/minio/minio-go.svg)](https://travis-ci.org/minio/minio-go) +[![Build status](https://ci.appveyor.com/api/projects/status/1d05e6nvxcelmrak?svg=true)](https://ci.appveyor.com/project/harshavardhana/minio-go) + diff --git a/vendor/github.com/minio/minio-go/api-compose-object.go b/vendor/github.com/minio/minio-go/api-compose-object.go new file mode 100644 index 0000000000000..3ac36c50223df --- /dev/null +++ b/vendor/github.com/minio/minio-go/api-compose-object.go @@ -0,0 +1,565 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2017, 2018 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package minio + +import ( + "context" + "fmt" + "io" + "io/ioutil" + "net/http" + "net/url" + "strconv" + "strings" + "time" + + "github.com/minio/minio-go/pkg/encrypt" + "github.com/minio/minio-go/pkg/s3utils" +) + +// DestinationInfo - type with information about the object to be +// created via server-side copy requests, using the Compose API. +type DestinationInfo struct { + bucket, object string + encryption encrypt.ServerSide + + // if no user-metadata is provided, it is copied from source + // (when there is only once source object in the compose + // request) + userMetadata map[string]string +} + +// NewDestinationInfo - creates a compose-object/copy-source +// destination info object. +// +// `encSSEC` is the key info for server-side-encryption with customer +// provided key. If it is nil, no encryption is performed. +// +// `userMeta` is the user-metadata key-value pairs to be set on the +// destination. The keys are automatically prefixed with `x-amz-meta-` +// if needed. If nil is passed, and if only a single source (of any +// size) is provided in the ComposeObject call, then metadata from the +// source is copied to the destination. +func NewDestinationInfo(bucket, object string, sse encrypt.ServerSide, userMeta map[string]string) (d DestinationInfo, err error) { + // Input validation. + if err = s3utils.CheckValidBucketName(bucket); err != nil { + return d, err + } + if err = s3utils.CheckValidObjectName(object); err != nil { + return d, err + } + + // Process custom-metadata to remove a `x-amz-meta-` prefix if + // present and validate that keys are distinct (after this + // prefix removal). + m := make(map[string]string) + for k, v := range userMeta { + if strings.HasPrefix(strings.ToLower(k), "x-amz-meta-") { + k = k[len("x-amz-meta-"):] + } + if _, ok := m[k]; ok { + return d, ErrInvalidArgument(fmt.Sprintf("Cannot add both %s and x-amz-meta-%s keys as custom metadata", k, k)) + } + m[k] = v + } + + return DestinationInfo{ + bucket: bucket, + object: object, + encryption: sse, + userMetadata: m, + }, nil +} + +// getUserMetaHeadersMap - construct appropriate key-value pairs to send +// as headers from metadata map to pass into copy-object request. For +// single part copy-object (i.e. non-multipart object), enable the +// withCopyDirectiveHeader to set the `x-amz-metadata-directive` to +// `REPLACE`, so that metadata headers from the source are not copied +// over. +func (d *DestinationInfo) getUserMetaHeadersMap(withCopyDirectiveHeader bool) map[string]string { + if len(d.userMetadata) == 0 { + return nil + } + r := make(map[string]string) + if withCopyDirectiveHeader { + r["x-amz-metadata-directive"] = "REPLACE" + } + for k, v := range d.userMetadata { + if isAmzHeader(k) || isStandardHeader(k) || isStorageClassHeader(k) { + r[k] = v + } else { + r["x-amz-meta-"+k] = v + } + } + return r +} + +// SourceInfo - represents a source object to be copied, using +// server-side copying APIs. +type SourceInfo struct { + bucket, object string + start, end int64 + encryption encrypt.ServerSide + // Headers to send with the upload-part-copy request involving + // this source object. + Headers http.Header +} + +// NewSourceInfo - create a compose-object/copy-object source info +// object. +// +// `decryptSSEC` is the decryption key using server-side-encryption +// with customer provided key. It may be nil if the source is not +// encrypted. +func NewSourceInfo(bucket, object string, sse encrypt.ServerSide) SourceInfo { + r := SourceInfo{ + bucket: bucket, + object: object, + start: -1, // range is unspecified by default + encryption: sse, + Headers: make(http.Header), + } + + // Set the source header + r.Headers.Set("x-amz-copy-source", s3utils.EncodePath(bucket+"/"+object)) + return r +} + +// SetRange - Set the start and end offset of the source object to be +// copied. If this method is not called, the whole source object is +// copied. +func (s *SourceInfo) SetRange(start, end int64) error { + if start > end || start < 0 { + return ErrInvalidArgument("start must be non-negative, and start must be at most end.") + } + // Note that 0 <= start <= end + s.start, s.end = start, end + return nil +} + +// SetMatchETagCond - Set ETag match condition. The object is copied +// only if the etag of the source matches the value given here. +func (s *SourceInfo) SetMatchETagCond(etag string) error { + if etag == "" { + return ErrInvalidArgument("ETag cannot be empty.") + } + s.Headers.Set("x-amz-copy-source-if-match", etag) + return nil +} + +// SetMatchETagExceptCond - Set the ETag match exception +// condition. The object is copied only if the etag of the source is +// not the value given here. +func (s *SourceInfo) SetMatchETagExceptCond(etag string) error { + if etag == "" { + return ErrInvalidArgument("ETag cannot be empty.") + } + s.Headers.Set("x-amz-copy-source-if-none-match", etag) + return nil +} + +// SetModifiedSinceCond - Set the modified since condition. +func (s *SourceInfo) SetModifiedSinceCond(modTime time.Time) error { + if modTime.IsZero() { + return ErrInvalidArgument("Input time cannot be 0.") + } + s.Headers.Set("x-amz-copy-source-if-modified-since", modTime.Format(http.TimeFormat)) + return nil +} + +// SetUnmodifiedSinceCond - Set the unmodified since condition. +func (s *SourceInfo) SetUnmodifiedSinceCond(modTime time.Time) error { + if modTime.IsZero() { + return ErrInvalidArgument("Input time cannot be 0.") + } + s.Headers.Set("x-amz-copy-source-if-unmodified-since", modTime.Format(http.TimeFormat)) + return nil +} + +// Helper to fetch size and etag of an object using a StatObject call. +func (s *SourceInfo) getProps(c Client) (size int64, etag string, userMeta map[string]string, err error) { + // Get object info - need size and etag here. Also, decryption + // headers are added to the stat request if given. + var objInfo ObjectInfo + opts := StatObjectOptions{GetObjectOptions{ServerSideEncryption: encrypt.SSE(s.encryption)}} + objInfo, err = c.statObject(context.Background(), s.bucket, s.object, opts) + if err != nil { + err = ErrInvalidArgument(fmt.Sprintf("Could not stat object - %s/%s: %v", s.bucket, s.object, err)) + } else { + size = objInfo.Size + etag = objInfo.ETag + userMeta = make(map[string]string) + for k, v := range objInfo.Metadata { + if strings.HasPrefix(k, "x-amz-meta-") { + if len(v) > 0 { + userMeta[k] = v[0] + } + } + } + } + return +} + +// Low level implementation of CopyObject API, supports only upto 5GiB worth of copy. +func (c Client) copyObjectDo(ctx context.Context, srcBucket, srcObject, destBucket, destObject string, + metadata map[string]string) (ObjectInfo, error) { + + // Build headers. + headers := make(http.Header) + + // Set all the metadata headers. + for k, v := range metadata { + headers.Set(k, v) + } + + // Set the source header + headers.Set("x-amz-copy-source", s3utils.EncodePath(srcBucket+"/"+srcObject)) + + // Send upload-part-copy request + resp, err := c.executeMethod(ctx, "PUT", requestMetadata{ + bucketName: destBucket, + objectName: destObject, + customHeader: headers, + }) + defer closeResponse(resp) + if err != nil { + return ObjectInfo{}, err + } + + // Check if we got an error response. + if resp.StatusCode != http.StatusOK { + return ObjectInfo{}, httpRespToErrorResponse(resp, srcBucket, srcObject) + } + + cpObjRes := copyObjectResult{} + err = xmlDecoder(resp.Body, &cpObjRes) + if err != nil { + return ObjectInfo{}, err + } + + objInfo := ObjectInfo{ + Key: destObject, + ETag: strings.Trim(cpObjRes.ETag, "\""), + LastModified: cpObjRes.LastModified, + } + return objInfo, nil +} + +func (c Client) copyObjectPartDo(ctx context.Context, srcBucket, srcObject, destBucket, destObject string, uploadID string, + partID int, startOffset int64, length int64, metadata map[string]string) (p CompletePart, err error) { + + headers := make(http.Header) + + // Set source + headers.Set("x-amz-copy-source", s3utils.EncodePath(srcBucket+"/"+srcObject)) + + if startOffset < 0 { + return p, ErrInvalidArgument("startOffset must be non-negative") + } + + if length >= 0 { + headers.Set("x-amz-copy-source-range", fmt.Sprintf("bytes=%d-%d", startOffset, startOffset+length-1)) + } + + for k, v := range metadata { + headers.Set(k, v) + } + + queryValues := make(url.Values) + queryValues.Set("partNumber", strconv.Itoa(partID)) + queryValues.Set("uploadId", uploadID) + + resp, err := c.executeMethod(ctx, "PUT", requestMetadata{ + bucketName: destBucket, + objectName: destObject, + customHeader: headers, + queryValues: queryValues, + }) + defer closeResponse(resp) + if err != nil { + return + } + + // Check if we got an error response. + if resp.StatusCode != http.StatusOK { + return p, httpRespToErrorResponse(resp, destBucket, destObject) + } + + // Decode copy-part response on success. + cpObjRes := copyObjectResult{} + err = xmlDecoder(resp.Body, &cpObjRes) + if err != nil { + return p, err + } + p.PartNumber, p.ETag = partID, cpObjRes.ETag + return p, nil +} + +// uploadPartCopy - helper function to create a part in a multipart +// upload via an upload-part-copy request +// https://docs.aws.amazon.com/AmazonS3/latest/API/mpUploadUploadPartCopy.html +func (c Client) uploadPartCopy(ctx context.Context, bucket, object, uploadID string, partNumber int, + headers http.Header) (p CompletePart, err error) { + + // Build query parameters + urlValues := make(url.Values) + urlValues.Set("partNumber", strconv.Itoa(partNumber)) + urlValues.Set("uploadId", uploadID) + + // Send upload-part-copy request + resp, err := c.executeMethod(ctx, "PUT", requestMetadata{ + bucketName: bucket, + objectName: object, + customHeader: headers, + queryValues: urlValues, + }) + defer closeResponse(resp) + if err != nil { + return p, err + } + + // Check if we got an error response. + if resp.StatusCode != http.StatusOK { + return p, httpRespToErrorResponse(resp, bucket, object) + } + + // Decode copy-part response on success. + cpObjRes := copyObjectResult{} + err = xmlDecoder(resp.Body, &cpObjRes) + if err != nil { + return p, err + } + p.PartNumber, p.ETag = partNumber, cpObjRes.ETag + return p, nil +} + +// ComposeObjectWithProgress - creates an object using server-side copying of +// existing objects. It takes a list of source objects (with optional +// offsets) and concatenates them into a new object using only +// server-side copying operations. Optionally takes progress reader hook +// for applications to look at current progress. +func (c Client) ComposeObjectWithProgress(dst DestinationInfo, srcs []SourceInfo, progress io.Reader) error { + if len(srcs) < 1 || len(srcs) > maxPartsCount { + return ErrInvalidArgument("There must be as least one and up to 10000 source objects.") + } + ctx := context.Background() + srcSizes := make([]int64, len(srcs)) + var totalSize, size, totalParts int64 + var srcUserMeta map[string]string + etags := make([]string, len(srcs)) + var err error + for i, src := range srcs { + size, etags[i], srcUserMeta, err = src.getProps(c) + if err != nil { + return err + } + + // Error out if client side encryption is used in this source object when + // more than one source objects are given. + if len(srcs) > 1 && src.Headers.Get("x-amz-meta-x-amz-key") != "" { + return ErrInvalidArgument( + fmt.Sprintf("Client side encryption is used in source object %s/%s", src.bucket, src.object)) + } + + // Check if a segment is specified, and if so, is the + // segment within object bounds? + if src.start != -1 { + // Since range is specified, + // 0 <= src.start <= src.end + // so only invalid case to check is: + if src.end >= size { + return ErrInvalidArgument( + fmt.Sprintf("SourceInfo %d has invalid segment-to-copy [%d, %d] (size is %d)", + i, src.start, src.end, size)) + } + size = src.end - src.start + 1 + } + + // Only the last source may be less than `absMinPartSize` + if size < absMinPartSize && i < len(srcs)-1 { + return ErrInvalidArgument( + fmt.Sprintf("SourceInfo %d is too small (%d) and it is not the last part", i, size)) + } + + // Is data to copy too large? + totalSize += size + if totalSize > maxMultipartPutObjectSize { + return ErrInvalidArgument(fmt.Sprintf("Cannot compose an object of size %d (> 5TiB)", totalSize)) + } + + // record source size + srcSizes[i] = size + + // calculate parts needed for current source + totalParts += partsRequired(size) + // Do we need more parts than we are allowed? + if totalParts > maxPartsCount { + return ErrInvalidArgument(fmt.Sprintf( + "Your proposed compose object requires more than %d parts", maxPartsCount)) + } + } + + // Single source object case (i.e. when only one source is + // involved, it is being copied wholly and at most 5GiB in + // size, emptyfiles are also supported). + if (totalParts == 1 && srcs[0].start == -1 && totalSize <= maxPartSize) || (totalSize == 0) { + return c.CopyObjectWithProgress(dst, srcs[0], progress) + } + + // Now, handle multipart-copy cases. + + // 1. Ensure that the object has not been changed while + // we are copying data. + for i, src := range srcs { + if src.Headers.Get("x-amz-copy-source-if-match") == "" { + src.SetMatchETagCond(etags[i]) + } + } + + // 2. Initiate a new multipart upload. + + // Set user-metadata on the destination object. If no + // user-metadata is specified, and there is only one source, + // (only) then metadata from source is copied. + userMeta := dst.getUserMetaHeadersMap(false) + metaMap := userMeta + if len(userMeta) == 0 && len(srcs) == 1 { + metaMap = srcUserMeta + } + metaHeaders := make(map[string]string) + for k, v := range metaMap { + metaHeaders[k] = v + } + + uploadID, err := c.newUploadID(ctx, dst.bucket, dst.object, PutObjectOptions{ServerSideEncryption: dst.encryption, UserMetadata: metaHeaders}) + if err != nil { + return err + } + + // 3. Perform copy part uploads + objParts := []CompletePart{} + partIndex := 1 + for i, src := range srcs { + h := src.Headers + if src.encryption != nil { + encrypt.SSECopy(src.encryption).Marshal(h) + } + // Add destination encryption headers + if dst.encryption != nil { + dst.encryption.Marshal(h) + } + + // calculate start/end indices of parts after + // splitting. + startIdx, endIdx := calculateEvenSplits(srcSizes[i], src) + for j, start := range startIdx { + end := endIdx[j] + + // Add (or reset) source range header for + // upload part copy request. + h.Set("x-amz-copy-source-range", + fmt.Sprintf("bytes=%d-%d", start, end)) + + // make upload-part-copy request + complPart, err := c.uploadPartCopy(ctx, dst.bucket, + dst.object, uploadID, partIndex, h) + if err != nil { + return err + } + if progress != nil { + io.CopyN(ioutil.Discard, progress, end-start+1) + } + objParts = append(objParts, complPart) + partIndex++ + } + } + + // 4. Make final complete-multipart request. + _, err = c.completeMultipartUpload(ctx, dst.bucket, dst.object, uploadID, + completeMultipartUpload{Parts: objParts}) + if err != nil { + return err + } + return nil +} + +// ComposeObject - creates an object using server-side copying of +// existing objects. It takes a list of source objects (with optional +// offsets) and concatenates them into a new object using only +// server-side copying operations. +func (c Client) ComposeObject(dst DestinationInfo, srcs []SourceInfo) error { + return c.ComposeObjectWithProgress(dst, srcs, nil) +} + +// partsRequired is maximum parts possible with +// max part size of ceiling(maxMultipartPutObjectSize / (maxPartsCount - 1)) +func partsRequired(size int64) int64 { + maxPartSize := maxMultipartPutObjectSize / (maxPartsCount - 1) + r := size / int64(maxPartSize) + if size%int64(maxPartSize) > 0 { + r++ + } + return r +} + +// calculateEvenSplits - computes splits for a source and returns +// start and end index slices. Splits happen evenly to be sure that no +// part is less than 5MiB, as that could fail the multipart request if +// it is not the last part. +func calculateEvenSplits(size int64, src SourceInfo) (startIndex, endIndex []int64) { + if size == 0 { + return + } + + reqParts := partsRequired(size) + startIndex = make([]int64, reqParts) + endIndex = make([]int64, reqParts) + // Compute number of required parts `k`, as: + // + // k = ceiling(size / copyPartSize) + // + // Now, distribute the `size` bytes in the source into + // k parts as evenly as possible: + // + // r parts sized (q+1) bytes, and + // (k - r) parts sized q bytes, where + // + // size = q * k + r (by simple division of size by k, + // so that 0 <= r < k) + // + start := src.start + if start == -1 { + start = 0 + } + quot, rem := size/reqParts, size%reqParts + nextStart := start + for j := int64(0); j < reqParts; j++ { + curPartSize := quot + if j < rem { + curPartSize++ + } + + cStart := nextStart + cEnd := cStart + curPartSize - 1 + nextStart = cEnd + 1 + + startIndex[j], endIndex[j] = cStart, cEnd + } + return +} diff --git a/vendor/github.com/minio/minio-go/api-datatypes.go b/vendor/github.com/minio/minio-go/api-datatypes.go new file mode 100644 index 0000000000000..63fc0890579c8 --- /dev/null +++ b/vendor/github.com/minio/minio-go/api-datatypes.go @@ -0,0 +1,84 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2015-2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package minio + +import ( + "net/http" + "time" +) + +// BucketInfo container for bucket metadata. +type BucketInfo struct { + // The name of the bucket. + Name string `json:"name"` + // Date the bucket was created. + CreationDate time.Time `json:"creationDate"` +} + +// ObjectInfo container for object metadata. +type ObjectInfo struct { + // An ETag is optionally set to md5sum of an object. In case of multipart objects, + // ETag is of the form MD5SUM-N where MD5SUM is md5sum of all individual md5sums of + // each parts concatenated into one string. + ETag string `json:"etag"` + + Key string `json:"name"` // Name of the object + LastModified time.Time `json:"lastModified"` // Date and time the object was last modified. + Size int64 `json:"size"` // Size in bytes of the object. + ContentType string `json:"contentType"` // A standard MIME type describing the format of the object data. + + // Collection of additional metadata on the object. + // eg: x-amz-meta-*, content-encoding etc. + Metadata http.Header `json:"metadata" xml:"-"` + + // Owner name. + Owner struct { + DisplayName string `json:"name"` + ID string `json:"id"` + } `json:"owner"` + + // The class of storage used to store the object. + StorageClass string `json:"storageClass"` + + // Error + Err error `json:"-"` +} + +// ObjectMultipartInfo container for multipart object metadata. +type ObjectMultipartInfo struct { + // Date and time at which the multipart upload was initiated. + Initiated time.Time `type:"timestamp" timestampFormat:"iso8601"` + + Initiator initiator + Owner owner + + // The type of storage to use for the object. Defaults to 'STANDARD'. + StorageClass string + + // Key of the object for which the multipart upload was initiated. + Key string + + // Size in bytes of the object. + Size int64 + + // Upload ID that identifies the multipart upload. + UploadID string `xml:"UploadId"` + + // Error + Err error +} diff --git a/vendor/github.com/minio/minio-go/api-error-response.go b/vendor/github.com/minio/minio-go/api-error-response.go new file mode 100644 index 0000000000000..0170b8de8093a --- /dev/null +++ b/vendor/github.com/minio/minio-go/api-error-response.go @@ -0,0 +1,282 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2015-2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package minio + +import ( + "encoding/xml" + "fmt" + "net/http" +) + +/* **** SAMPLE ERROR RESPONSE **** + + + AccessDenied + Access Denied + bucketName + objectName + F19772218238A85A + GuWkjyviSiGHizehqpmsD1ndz5NClSP19DOT+s2mv7gXGQ8/X1lhbDGiIJEXpGFD + +*/ + +// ErrorResponse - Is the typed error returned by all API operations. +// ErrorResponse struct should be comparable since it is compared inside +// golang http API (https://github.com/golang/go/issues/29768) +type ErrorResponse struct { + XMLName xml.Name `xml:"Error" json:"-"` + Code string + Message string + BucketName string + Key string + RequestID string `xml:"RequestId"` + HostID string `xml:"HostId"` + + // Region where the bucket is located. This header is returned + // only in HEAD bucket and ListObjects response. + Region string + + // Underlying HTTP status code for the returned error + StatusCode int `xml:"-" json:"-"` +} + +// ToErrorResponse - Returns parsed ErrorResponse struct from body and +// http headers. +// +// For example: +// +// import s3 "github.com/minio/minio-go" +// ... +// ... +// reader, stat, err := s3.GetObject(...) +// if err != nil { +// resp := s3.ToErrorResponse(err) +// } +// ... +func ToErrorResponse(err error) ErrorResponse { + switch err := err.(type) { + case ErrorResponse: + return err + default: + return ErrorResponse{} + } +} + +// Error - Returns S3 error string. +func (e ErrorResponse) Error() string { + if e.Message == "" { + msg, ok := s3ErrorResponseMap[e.Code] + if !ok { + msg = fmt.Sprintf("Error response code %s.", e.Code) + } + return msg + } + return e.Message +} + +// Common string for errors to report issue location in unexpected +// cases. +const ( + reportIssue = "Please report this issue at https://github.com/minio/minio-go/issues." +) + +// httpRespToErrorResponse returns a new encoded ErrorResponse +// structure as error. +func httpRespToErrorResponse(resp *http.Response, bucketName, objectName string) error { + if resp == nil { + msg := "Response is empty. " + reportIssue + return ErrInvalidArgument(msg) + } + + errResp := ErrorResponse{ + StatusCode: resp.StatusCode, + } + + err := xmlDecoder(resp.Body, &errResp) + // Xml decoding failed with no body, fall back to HTTP headers. + if err != nil { + switch resp.StatusCode { + case http.StatusNotFound: + if objectName == "" { + errResp = ErrorResponse{ + StatusCode: resp.StatusCode, + Code: "NoSuchBucket", + Message: "The specified bucket does not exist.", + BucketName: bucketName, + } + } else { + errResp = ErrorResponse{ + StatusCode: resp.StatusCode, + Code: "NoSuchKey", + Message: "The specified key does not exist.", + BucketName: bucketName, + Key: objectName, + } + } + case http.StatusForbidden: + errResp = ErrorResponse{ + StatusCode: resp.StatusCode, + Code: "AccessDenied", + Message: "Access Denied.", + BucketName: bucketName, + Key: objectName, + } + case http.StatusConflict: + errResp = ErrorResponse{ + StatusCode: resp.StatusCode, + Code: "Conflict", + Message: "Bucket not empty.", + BucketName: bucketName, + } + case http.StatusPreconditionFailed: + errResp = ErrorResponse{ + StatusCode: resp.StatusCode, + Code: "PreconditionFailed", + Message: s3ErrorResponseMap["PreconditionFailed"], + BucketName: bucketName, + Key: objectName, + } + default: + errResp = ErrorResponse{ + StatusCode: resp.StatusCode, + Code: resp.Status, + Message: resp.Status, + BucketName: bucketName, + } + } + } + + // Save hostID, requestID and region information + // from headers if not available through error XML. + if errResp.RequestID == "" { + errResp.RequestID = resp.Header.Get("x-amz-request-id") + } + if errResp.HostID == "" { + errResp.HostID = resp.Header.Get("x-amz-id-2") + } + if errResp.Region == "" { + errResp.Region = resp.Header.Get("x-amz-bucket-region") + } + if errResp.Code == "InvalidRegion" && errResp.Region != "" { + errResp.Message = fmt.Sprintf("Region does not match, expecting region ‘%s’.", errResp.Region) + } + + return errResp +} + +// ErrTransferAccelerationBucket - bucket name is invalid to be used with transfer acceleration. +func ErrTransferAccelerationBucket(bucketName string) error { + return ErrorResponse{ + StatusCode: http.StatusBadRequest, + Code: "InvalidArgument", + Message: "The name of the bucket used for Transfer Acceleration must be DNS-compliant and must not contain periods ‘.’.", + BucketName: bucketName, + } +} + +// ErrEntityTooLarge - Input size is larger than supported maximum. +func ErrEntityTooLarge(totalSize, maxObjectSize int64, bucketName, objectName string) error { + msg := fmt.Sprintf("Your proposed upload size ‘%d’ exceeds the maximum allowed object size ‘%d’ for single PUT operation.", totalSize, maxObjectSize) + return ErrorResponse{ + StatusCode: http.StatusBadRequest, + Code: "EntityTooLarge", + Message: msg, + BucketName: bucketName, + Key: objectName, + } +} + +// ErrEntityTooSmall - Input size is smaller than supported minimum. +func ErrEntityTooSmall(totalSize int64, bucketName, objectName string) error { + msg := fmt.Sprintf("Your proposed upload size ‘%d’ is below the minimum allowed object size ‘0B’ for single PUT operation.", totalSize) + return ErrorResponse{ + StatusCode: http.StatusBadRequest, + Code: "EntityTooSmall", + Message: msg, + BucketName: bucketName, + Key: objectName, + } +} + +// ErrUnexpectedEOF - Unexpected end of file reached. +func ErrUnexpectedEOF(totalRead, totalSize int64, bucketName, objectName string) error { + msg := fmt.Sprintf("Data read ‘%d’ is not equal to the size ‘%d’ of the input Reader.", totalRead, totalSize) + return ErrorResponse{ + StatusCode: http.StatusBadRequest, + Code: "UnexpectedEOF", + Message: msg, + BucketName: bucketName, + Key: objectName, + } +} + +// ErrInvalidBucketName - Invalid bucket name response. +func ErrInvalidBucketName(message string) error { + return ErrorResponse{ + StatusCode: http.StatusBadRequest, + Code: "InvalidBucketName", + Message: message, + RequestID: "minio", + } +} + +// ErrInvalidObjectName - Invalid object name response. +func ErrInvalidObjectName(message string) error { + return ErrorResponse{ + StatusCode: http.StatusNotFound, + Code: "NoSuchKey", + Message: message, + RequestID: "minio", + } +} + +// ErrInvalidObjectPrefix - Invalid object prefix response is +// similar to object name response. +var ErrInvalidObjectPrefix = ErrInvalidObjectName + +// ErrInvalidArgument - Invalid argument response. +func ErrInvalidArgument(message string) error { + return ErrorResponse{ + StatusCode: http.StatusBadRequest, + Code: "InvalidArgument", + Message: message, + RequestID: "minio", + } +} + +// ErrNoSuchBucketPolicy - No Such Bucket Policy response +// The specified bucket does not have a bucket policy. +func ErrNoSuchBucketPolicy(message string) error { + return ErrorResponse{ + StatusCode: http.StatusNotFound, + Code: "NoSuchBucketPolicy", + Message: message, + RequestID: "minio", + } +} + +// ErrAPINotSupported - API not supported response +// The specified API call is not supported +func ErrAPINotSupported(message string) error { + return ErrorResponse{ + StatusCode: http.StatusNotImplemented, + Code: "APINotSupported", + Message: message, + RequestID: "minio", + } +} diff --git a/vendor/github.com/minio/minio-go/api-get-lifecycle.go b/vendor/github.com/minio/minio-go/api-get-lifecycle.go new file mode 100644 index 0000000000000..8097bfc02e80d --- /dev/null +++ b/vendor/github.com/minio/minio-go/api-get-lifecycle.go @@ -0,0 +1,77 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2015-2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package minio + +import ( + "context" + "io/ioutil" + "net/http" + "net/url" + + "github.com/minio/minio-go/pkg/s3utils" +) + +// GetBucketLifecycle - get bucket lifecycle. +func (c Client) GetBucketLifecycle(bucketName string) (string, error) { + // Input validation. + if err := s3utils.CheckValidBucketName(bucketName); err != nil { + return "", err + } + bucketLifecycle, err := c.getBucketLifecycle(bucketName) + if err != nil { + errResponse := ToErrorResponse(err) + if errResponse.Code == "NoSuchLifecycleConfiguration" { + return "", nil + } + return "", err + } + return bucketLifecycle, nil +} + +// Request server for current bucket lifecycle. +func (c Client) getBucketLifecycle(bucketName string) (string, error) { + // Get resources properly escaped and lined up before + // using them in http request. + urlValues := make(url.Values) + urlValues.Set("lifecycle", "") + + // Execute GET on bucket to get lifecycle. + resp, err := c.executeMethod(context.Background(), "GET", requestMetadata{ + bucketName: bucketName, + queryValues: urlValues, + }) + + defer closeResponse(resp) + if err != nil { + return "", err + } + + if resp != nil { + if resp.StatusCode != http.StatusOK { + return "", httpRespToErrorResponse(resp, bucketName, "") + } + } + + bucketLifecycleBuf, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", err + } + + lifecycle := string(bucketLifecycleBuf) + return lifecycle, err +} diff --git a/vendor/github.com/minio/minio-go/api-get-object-acl.go b/vendor/github.com/minio/minio-go/api-get-object-acl.go new file mode 100644 index 0000000000000..af5544da31a25 --- /dev/null +++ b/vendor/github.com/minio/minio-go/api-get-object-acl.go @@ -0,0 +1,136 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2018 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package minio + +import ( + "context" + "net/http" + "net/url" +) + +type accessControlPolicy struct { + Owner struct { + ID string `xml:"ID"` + DisplayName string `xml:"DisplayName"` + } `xml:"Owner"` + AccessControlList struct { + Grant []struct { + Grantee struct { + ID string `xml:"ID"` + DisplayName string `xml:"DisplayName"` + URI string `xml:"URI"` + } `xml:"Grantee"` + Permission string `xml:"Permission"` + } `xml:"Grant"` + } `xml:"AccessControlList"` +} + +//GetObjectACL get object ACLs +func (c Client) GetObjectACL(bucketName, objectName string) (*ObjectInfo, error) { + + resp, err := c.executeMethod(context.Background(), "GET", requestMetadata{ + bucketName: bucketName, + objectName: objectName, + queryValues: url.Values{ + "acl": []string{""}, + }, + }) + if err != nil { + return nil, err + } + defer closeResponse(resp) + + if resp.StatusCode != http.StatusOK { + return nil, httpRespToErrorResponse(resp, bucketName, objectName) + } + + res := &accessControlPolicy{} + + if err := xmlDecoder(resp.Body, res); err != nil { + return nil, err + } + + objInfo, err := c.statObject(context.Background(), bucketName, objectName, StatObjectOptions{}) + if err != nil { + return nil, err + } + + cannedACL := getCannedACL(res) + if cannedACL != "" { + objInfo.Metadata.Add("X-Amz-Acl", cannedACL) + return &objInfo, nil + } + + grantACL := getAmzGrantACL(res) + for k, v := range grantACL { + objInfo.Metadata[k] = v + } + + return &objInfo, nil +} + +func getCannedACL(aCPolicy *accessControlPolicy) string { + grants := aCPolicy.AccessControlList.Grant + + switch { + case len(grants) == 1: + if grants[0].Grantee.URI == "" && grants[0].Permission == "FULL_CONTROL" { + return "private" + } + case len(grants) == 2: + for _, g := range grants { + if g.Grantee.URI == "http://acs.amazonaws.com/groups/global/AuthenticatedUsers" && g.Permission == "READ" { + return "authenticated-read" + } + if g.Grantee.URI == "http://acs.amazonaws.com/groups/global/AllUsers" && g.Permission == "READ" { + return "public-read" + } + if g.Permission == "READ" && g.Grantee.ID == aCPolicy.Owner.ID { + return "bucket-owner-read" + } + } + case len(grants) == 3: + for _, g := range grants { + if g.Grantee.URI == "http://acs.amazonaws.com/groups/global/AllUsers" && g.Permission == "WRITE" { + return "public-read-write" + } + } + } + return "" +} + +func getAmzGrantACL(aCPolicy *accessControlPolicy) map[string][]string { + grants := aCPolicy.AccessControlList.Grant + res := map[string][]string{} + + for _, g := range grants { + switch { + case g.Permission == "READ": + res["X-Amz-Grant-Read"] = append(res["X-Amz-Grant-Read"], "id="+g.Grantee.ID) + case g.Permission == "WRITE": + res["X-Amz-Grant-Write"] = append(res["X-Amz-Grant-Write"], "id="+g.Grantee.ID) + case g.Permission == "READ_ACP": + res["X-Amz-Grant-Read-Acp"] = append(res["X-Amz-Grant-Read-Acp"], "id="+g.Grantee.ID) + case g.Permission == "WRITE_ACP": + res["X-Amz-Grant-Write-Acp"] = append(res["X-Amz-Grant-Write-Acp"], "id="+g.Grantee.ID) + case g.Permission == "FULL_CONTROL": + res["X-Amz-Grant-Full-Control"] = append(res["X-Amz-Grant-Full-Control"], "id="+g.Grantee.ID) + } + } + return res +} diff --git a/vendor/github.com/minio/minio-go/api-get-object-context.go b/vendor/github.com/minio/minio-go/api-get-object-context.go new file mode 100644 index 0000000000000..f8dfac7d6b11e --- /dev/null +++ b/vendor/github.com/minio/minio-go/api-get-object-context.go @@ -0,0 +1,26 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package minio + +import "context" + +// GetObjectWithContext - returns an seekable, readable object. +// The options can be used to specify the GET request further. +func (c Client) GetObjectWithContext(ctx context.Context, bucketName, objectName string, opts GetObjectOptions) (*Object, error) { + return c.getObjectWithContext(ctx, bucketName, objectName, opts) +} diff --git a/vendor/github.com/minio/minio-go/api-get-object-file.go b/vendor/github.com/minio/minio-go/api-get-object-file.go new file mode 100644 index 0000000000000..a852220a235c7 --- /dev/null +++ b/vendor/github.com/minio/minio-go/api-get-object-file.go @@ -0,0 +1,125 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2015-2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package minio + +import ( + "context" + "io" + "os" + "path/filepath" + + "github.com/minio/minio-go/pkg/s3utils" +) + +// FGetObjectWithContext - download contents of an object to a local file. +// The options can be used to specify the GET request further. +func (c Client) FGetObjectWithContext(ctx context.Context, bucketName, objectName, filePath string, opts GetObjectOptions) error { + return c.fGetObjectWithContext(ctx, bucketName, objectName, filePath, opts) +} + +// FGetObject - download contents of an object to a local file. +func (c Client) FGetObject(bucketName, objectName, filePath string, opts GetObjectOptions) error { + return c.fGetObjectWithContext(context.Background(), bucketName, objectName, filePath, opts) +} + +// fGetObjectWithContext - fgetObject wrapper function with context +func (c Client) fGetObjectWithContext(ctx context.Context, bucketName, objectName, filePath string, opts GetObjectOptions) error { + // Input validation. + if err := s3utils.CheckValidBucketName(bucketName); err != nil { + return err + } + if err := s3utils.CheckValidObjectName(objectName); err != nil { + return err + } + + // Verify if destination already exists. + st, err := os.Stat(filePath) + if err == nil { + // If the destination exists and is a directory. + if st.IsDir() { + return ErrInvalidArgument("fileName is a directory.") + } + } + + // Proceed if file does not exist. return for all other errors. + if err != nil { + if !os.IsNotExist(err) { + return err + } + } + + // Extract top level directory. + objectDir, _ := filepath.Split(filePath) + if objectDir != "" { + // Create any missing top level directories. + if err := os.MkdirAll(objectDir, 0700); err != nil { + return err + } + } + + // Gather md5sum. + objectStat, err := c.StatObject(bucketName, objectName, StatObjectOptions{opts}) + if err != nil { + return err + } + + // Write to a temporary file "fileName.part.minio" before saving. + filePartPath := filePath + objectStat.ETag + ".part.minio" + + // If exists, open in append mode. If not create it as a part file. + filePart, err := os.OpenFile(filePartPath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600) + if err != nil { + return err + } + + // Issue Stat to get the current offset. + st, err = filePart.Stat() + if err != nil { + return err + } + + // Initialize get object request headers to set the + // appropriate range offsets to read from. + if st.Size() > 0 { + opts.SetRange(st.Size(), 0) + } + + // Seek to current position for incoming reader. + objectReader, objectStat, err := c.getObject(ctx, bucketName, objectName, opts) + if err != nil { + return err + } + + // Write to the part file. + if _, err = io.CopyN(filePart, objectReader, objectStat.Size); err != nil { + return err + } + + // Close the file before rename, this is specifically needed for Windows users. + if err = filePart.Close(); err != nil { + return err + } + + // Safely completed. Now commit by renaming to actual filename. + if err = os.Rename(filePartPath, filePath); err != nil { + return err + } + + // Return. + return nil +} diff --git a/vendor/github.com/minio/minio-go/api-get-object.go b/vendor/github.com/minio/minio-go/api-get-object.go new file mode 100644 index 0000000000000..0bf556ec68d56 --- /dev/null +++ b/vendor/github.com/minio/minio-go/api-get-object.go @@ -0,0 +1,659 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2015-2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package minio + +import ( + "context" + "errors" + "fmt" + "io" + "net/http" + "strings" + "sync" + "time" + + "github.com/minio/minio-go/pkg/s3utils" +) + +// GetObject - returns an seekable, readable object. +func (c Client) GetObject(bucketName, objectName string, opts GetObjectOptions) (*Object, error) { + return c.getObjectWithContext(context.Background(), bucketName, objectName, opts) +} + +// GetObject wrapper function that accepts a request context +func (c Client) getObjectWithContext(ctx context.Context, bucketName, objectName string, opts GetObjectOptions) (*Object, error) { + // Input validation. + if err := s3utils.CheckValidBucketName(bucketName); err != nil { + return nil, err + } + if err := s3utils.CheckValidObjectName(objectName); err != nil { + return nil, err + } + + var httpReader io.ReadCloser + var objectInfo ObjectInfo + var err error + + // Create request channel. + reqCh := make(chan getRequest) + // Create response channel. + resCh := make(chan getResponse) + // Create done channel. + doneCh := make(chan struct{}) + + // This routine feeds partial object data as and when the caller reads. + go func() { + defer close(reqCh) + defer close(resCh) + + // Used to verify if etag of object has changed since last read. + var etag string + + // Loop through the incoming control messages and read data. + for { + select { + // When the done channel is closed exit our routine. + case <-doneCh: + // Close the http response body before returning. + // This ends the connection with the server. + if httpReader != nil { + httpReader.Close() + } + return + + // Gather incoming request. + case req := <-reqCh: + // If this is the first request we may not need to do a getObject request yet. + if req.isFirstReq { + // First request is a Read/ReadAt. + if req.isReadOp { + // Differentiate between wanting the whole object and just a range. + if req.isReadAt { + // If this is a ReadAt request only get the specified range. + // Range is set with respect to the offset and length of the buffer requested. + // Do not set objectInfo from the first readAt request because it will not get + // the whole object. + opts.SetRange(req.Offset, req.Offset+int64(len(req.Buffer))-1) + } else if req.Offset > 0 { + opts.SetRange(req.Offset, 0) + } + httpReader, objectInfo, err = c.getObject(ctx, bucketName, objectName, opts) + if err != nil { + resCh <- getResponse{Error: err} + return + } + etag = objectInfo.ETag + // Read at least firstReq.Buffer bytes, if not we have + // reached our EOF. + size, err := io.ReadFull(httpReader, req.Buffer) + if size > 0 && err == io.ErrUnexpectedEOF { + // If an EOF happens after reading some but not + // all the bytes ReadFull returns ErrUnexpectedEOF + err = io.EOF + } + // Send back the first response. + resCh <- getResponse{ + objectInfo: objectInfo, + Size: int(size), + Error: err, + didRead: true, + } + } else { + // First request is a Stat or Seek call. + // Only need to run a StatObject until an actual Read or ReadAt request comes through. + + // Remove range header if already set, for stat Operations to get original file size. + delete(opts.headers, "Range") + objectInfo, err = c.statObject(ctx, bucketName, objectName, StatObjectOptions{opts}) + if err != nil { + resCh <- getResponse{ + Error: err, + } + // Exit the go-routine. + return + } + etag = objectInfo.ETag + // Send back the first response. + resCh <- getResponse{ + objectInfo: objectInfo, + } + } + } else if req.settingObjectInfo { // Request is just to get objectInfo. + // Remove range header if already set, for stat Operations to get original file size. + delete(opts.headers, "Range") + if etag != "" { + opts.SetMatchETag(etag) + } + objectInfo, err := c.statObject(ctx, bucketName, objectName, StatObjectOptions{opts}) + if err != nil { + resCh <- getResponse{ + Error: err, + } + // Exit the goroutine. + return + } + // Send back the objectInfo. + resCh <- getResponse{ + objectInfo: objectInfo, + } + } else { + // Offset changes fetch the new object at an Offset. + // Because the httpReader may not be set by the first + // request if it was a stat or seek it must be checked + // if the object has been read or not to only initialize + // new ones when they haven't been already. + // All readAt requests are new requests. + if req.DidOffsetChange || !req.beenRead { + if etag != "" { + opts.SetMatchETag(etag) + } + if httpReader != nil { + // Close previously opened http reader. + httpReader.Close() + } + // If this request is a readAt only get the specified range. + if req.isReadAt { + // Range is set with respect to the offset and length of the buffer requested. + opts.SetRange(req.Offset, req.Offset+int64(len(req.Buffer))-1) + } else if req.Offset > 0 { // Range is set with respect to the offset. + opts.SetRange(req.Offset, 0) + } + httpReader, objectInfo, err = c.getObject(ctx, bucketName, objectName, opts) + if err != nil { + resCh <- getResponse{ + Error: err, + } + return + } + } + + // Read at least req.Buffer bytes, if not we have + // reached our EOF. + size, err := io.ReadFull(httpReader, req.Buffer) + if err == io.ErrUnexpectedEOF { + // If an EOF happens after reading some but not + // all the bytes ReadFull returns ErrUnexpectedEOF + err = io.EOF + } + // Reply back how much was read. + resCh <- getResponse{ + Size: int(size), + Error: err, + didRead: true, + objectInfo: objectInfo, + } + } + } + } + }() + + // Create a newObject through the information sent back by reqCh. + return newObject(reqCh, resCh, doneCh), nil +} + +// get request message container to communicate with internal +// go-routine. +type getRequest struct { + Buffer []byte + Offset int64 // readAt offset. + DidOffsetChange bool // Tracks the offset changes for Seek requests. + beenRead bool // Determines if this is the first time an object is being read. + isReadAt bool // Determines if this request is a request to a specific range + isReadOp bool // Determines if this request is a Read or Read/At request. + isFirstReq bool // Determines if this request is the first time an object is being accessed. + settingObjectInfo bool // Determines if this request is to set the objectInfo of an object. +} + +// get response message container to reply back for the request. +type getResponse struct { + Size int + Error error + didRead bool // Lets subsequent calls know whether or not httpReader has been initiated. + objectInfo ObjectInfo // Used for the first request. +} + +// Object represents an open object. It implements +// Reader, ReaderAt, Seeker, Closer for a HTTP stream. +type Object struct { + // Mutex. + mutex *sync.Mutex + + // User allocated and defined. + reqCh chan<- getRequest + resCh <-chan getResponse + doneCh chan<- struct{} + currOffset int64 + objectInfo ObjectInfo + + // Ask lower level to initiate data fetching based on currOffset + seekData bool + + // Keeps track of closed call. + isClosed bool + + // Keeps track of if this is the first call. + isStarted bool + + // Previous error saved for future calls. + prevErr error + + // Keeps track of if this object has been read yet. + beenRead bool + + // Keeps track of if objectInfo has been set yet. + objectInfoSet bool +} + +// doGetRequest - sends and blocks on the firstReqCh and reqCh of an object. +// Returns back the size of the buffer read, if anything was read, as well +// as any error encountered. For all first requests sent on the object +// it is also responsible for sending back the objectInfo. +func (o *Object) doGetRequest(request getRequest) (getResponse, error) { + o.reqCh <- request + response := <-o.resCh + + // Return any error to the top level. + if response.Error != nil { + return response, response.Error + } + + // This was the first request. + if !o.isStarted { + // The object has been operated on. + o.isStarted = true + } + // Set the objectInfo if the request was not readAt + // and it hasn't been set before. + if !o.objectInfoSet && !request.isReadAt { + o.objectInfo = response.objectInfo + o.objectInfoSet = true + } + // Set beenRead only if it has not been set before. + if !o.beenRead { + o.beenRead = response.didRead + } + // Data are ready on the wire, no need to reinitiate connection in lower level + o.seekData = false + + return response, nil +} + +// setOffset - handles the setting of offsets for +// Read/ReadAt/Seek requests. +func (o *Object) setOffset(bytesRead int64) error { + // Update the currentOffset. + o.currOffset += bytesRead + + if o.objectInfo.Size > -1 && o.currOffset >= o.objectInfo.Size { + return io.EOF + } + return nil +} + +// Read reads up to len(b) bytes into b. It returns the number of +// bytes read (0 <= n <= len(b)) and any error encountered. Returns +// io.EOF upon end of file. +func (o *Object) Read(b []byte) (n int, err error) { + if o == nil { + return 0, ErrInvalidArgument("Object is nil") + } + + // Locking. + o.mutex.Lock() + defer o.mutex.Unlock() + + // prevErr is previous error saved from previous operation. + if o.prevErr != nil || o.isClosed { + return 0, o.prevErr + } + // Create a new request. + readReq := getRequest{ + isReadOp: true, + beenRead: o.beenRead, + Buffer: b, + } + + // Alert that this is the first request. + if !o.isStarted { + readReq.isFirstReq = true + } + + // Ask to establish a new data fetch routine based on seekData flag + readReq.DidOffsetChange = o.seekData + readReq.Offset = o.currOffset + + // Send and receive from the first request. + response, err := o.doGetRequest(readReq) + if err != nil && err != io.EOF { + // Save the error for future calls. + o.prevErr = err + return response.Size, err + } + + // Bytes read. + bytesRead := int64(response.Size) + + // Set the new offset. + oerr := o.setOffset(bytesRead) + if oerr != nil { + // Save the error for future calls. + o.prevErr = oerr + return response.Size, oerr + } + + // Return the response. + return response.Size, err +} + +// Stat returns the ObjectInfo structure describing Object. +func (o *Object) Stat() (ObjectInfo, error) { + if o == nil { + return ObjectInfo{}, ErrInvalidArgument("Object is nil") + } + // Locking. + o.mutex.Lock() + defer o.mutex.Unlock() + + if o.prevErr != nil && o.prevErr != io.EOF || o.isClosed { + return ObjectInfo{}, o.prevErr + } + + // This is the first request. + if !o.isStarted || !o.objectInfoSet { + // Send the request and get the response. + _, err := o.doGetRequest(getRequest{ + isFirstReq: !o.isStarted, + settingObjectInfo: !o.objectInfoSet, + }) + if err != nil { + o.prevErr = err + return ObjectInfo{}, err + } + } + + return o.objectInfo, nil +} + +// ReadAt reads len(b) bytes from the File starting at byte offset +// off. It returns the number of bytes read and the error, if any. +// ReadAt always returns a non-nil error when n < len(b). At end of +// file, that error is io.EOF. +func (o *Object) ReadAt(b []byte, offset int64) (n int, err error) { + if o == nil { + return 0, ErrInvalidArgument("Object is nil") + } + + // Locking. + o.mutex.Lock() + defer o.mutex.Unlock() + + // prevErr is error which was saved in previous operation. + if o.prevErr != nil || o.isClosed { + return 0, o.prevErr + } + + // Can only compare offsets to size when size has been set. + if o.objectInfoSet { + // If offset is negative than we return io.EOF. + // If offset is greater than or equal to object size we return io.EOF. + if (o.objectInfo.Size > -1 && offset >= o.objectInfo.Size) || offset < 0 { + return 0, io.EOF + } + } + + // Create the new readAt request. + readAtReq := getRequest{ + isReadOp: true, + isReadAt: true, + DidOffsetChange: true, // Offset always changes. + beenRead: o.beenRead, // Set if this is the first request to try and read. + Offset: offset, // Set the offset. + Buffer: b, + } + + // Alert that this is the first request. + if !o.isStarted { + readAtReq.isFirstReq = true + } + + // Send and receive from the first request. + response, err := o.doGetRequest(readAtReq) + if err != nil && err != io.EOF { + // Save the error. + o.prevErr = err + return response.Size, err + } + // Bytes read. + bytesRead := int64(response.Size) + // There is no valid objectInfo yet + // to compare against for EOF. + if !o.objectInfoSet { + // Update the currentOffset. + o.currOffset += bytesRead + } else { + // If this was not the first request update + // the offsets and compare against objectInfo + // for EOF. + oerr := o.setOffset(bytesRead) + if oerr != nil { + o.prevErr = oerr + return response.Size, oerr + } + } + return response.Size, err +} + +// Seek sets the offset for the next Read or Write to offset, +// interpreted according to whence: 0 means relative to the +// origin of the file, 1 means relative to the current offset, +// and 2 means relative to the end. +// Seek returns the new offset and an error, if any. +// +// Seeking to a negative offset is an error. Seeking to any positive +// offset is legal, subsequent io operations succeed until the +// underlying object is not closed. +func (o *Object) Seek(offset int64, whence int) (n int64, err error) { + if o == nil { + return 0, ErrInvalidArgument("Object is nil") + } + + // Locking. + o.mutex.Lock() + defer o.mutex.Unlock() + + if o.prevErr != nil { + // At EOF seeking is legal allow only io.EOF, for any other errors we return. + if o.prevErr != io.EOF { + return 0, o.prevErr + } + } + + // Negative offset is valid for whence of '2'. + if offset < 0 && whence != 2 { + return 0, ErrInvalidArgument(fmt.Sprintf("Negative position not allowed for %d", whence)) + } + + // This is the first request. So before anything else + // get the ObjectInfo. + if !o.isStarted || !o.objectInfoSet { + // Create the new Seek request. + seekReq := getRequest{ + isReadOp: false, + Offset: offset, + isFirstReq: true, + } + // Send and receive from the seek request. + _, err := o.doGetRequest(seekReq) + if err != nil { + // Save the error. + o.prevErr = err + return 0, err + } + } + + // Switch through whence. + switch whence { + default: + return 0, ErrInvalidArgument(fmt.Sprintf("Invalid whence %d", whence)) + case 0: + if o.objectInfo.Size > -1 && offset > o.objectInfo.Size { + return 0, io.EOF + } + o.currOffset = offset + case 1: + if o.objectInfo.Size > -1 && o.currOffset+offset > o.objectInfo.Size { + return 0, io.EOF + } + o.currOffset += offset + case 2: + // If we don't know the object size return an error for io.SeekEnd + if o.objectInfo.Size < 0 { + return 0, ErrInvalidArgument("Whence END is not supported when the object size is unknown") + } + // Seeking to positive offset is valid for whence '2', but + // since we are backing a Reader we have reached 'EOF' if + // offset is positive. + if offset > 0 { + return 0, io.EOF + } + // Seeking to negative position not allowed for whence. + if o.objectInfo.Size+offset < 0 { + return 0, ErrInvalidArgument(fmt.Sprintf("Seeking at negative offset not allowed for %d", whence)) + } + o.currOffset = o.objectInfo.Size + offset + } + // Reset the saved error since we successfully seeked, let the Read + // and ReadAt decide. + if o.prevErr == io.EOF { + o.prevErr = nil + } + + // Ask lower level to fetch again from source + o.seekData = true + + // Return the effective offset. + return o.currOffset, nil +} + +// Close - The behavior of Close after the first call returns error +// for subsequent Close() calls. +func (o *Object) Close() (err error) { + if o == nil { + return ErrInvalidArgument("Object is nil") + } + // Locking. + o.mutex.Lock() + defer o.mutex.Unlock() + + // if already closed return an error. + if o.isClosed { + return o.prevErr + } + + // Close successfully. + close(o.doneCh) + + // Save for future operations. + errMsg := "Object is already closed. Bad file descriptor." + o.prevErr = errors.New(errMsg) + // Save here that we closed done channel successfully. + o.isClosed = true + return nil +} + +// newObject instantiates a new *minio.Object* +// ObjectInfo will be set by setObjectInfo +func newObject(reqCh chan<- getRequest, resCh <-chan getResponse, doneCh chan<- struct{}) *Object { + return &Object{ + mutex: &sync.Mutex{}, + reqCh: reqCh, + resCh: resCh, + doneCh: doneCh, + } +} + +// getObject - retrieve object from Object Storage. +// +// Additionally this function also takes range arguments to download the specified +// range bytes of an object. Setting offset and length = 0 will download the full object. +// +// For more information about the HTTP Range header. +// go to http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35. +func (c Client) getObject(ctx context.Context, bucketName, objectName string, opts GetObjectOptions) (io.ReadCloser, ObjectInfo, error) { + // Validate input arguments. + if err := s3utils.CheckValidBucketName(bucketName); err != nil { + return nil, ObjectInfo{}, err + } + if err := s3utils.CheckValidObjectName(objectName); err != nil { + return nil, ObjectInfo{}, err + } + + // Execute GET on objectName. + resp, err := c.executeMethod(ctx, "GET", requestMetadata{ + bucketName: bucketName, + objectName: objectName, + customHeader: opts.Header(), + contentSHA256Hex: emptySHA256Hex, + }) + if err != nil { + return nil, ObjectInfo{}, err + } + if resp != nil { + if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusPartialContent { + return nil, ObjectInfo{}, httpRespToErrorResponse(resp, bucketName, objectName) + } + } + + // Trim off the odd double quotes from ETag in the beginning and end. + md5sum := strings.TrimPrefix(resp.Header.Get("ETag"), "\"") + md5sum = strings.TrimSuffix(md5sum, "\"") + + // Parse the date. + date, err := time.Parse(http.TimeFormat, resp.Header.Get("Last-Modified")) + if err != nil { + msg := "Last-Modified time format not recognized. " + reportIssue + return nil, ObjectInfo{}, ErrorResponse{ + Code: "InternalError", + Message: msg, + RequestID: resp.Header.Get("x-amz-request-id"), + HostID: resp.Header.Get("x-amz-id-2"), + Region: resp.Header.Get("x-amz-bucket-region"), + } + } + + // Get content-type. + contentType := strings.TrimSpace(resp.Header.Get("Content-Type")) + if contentType == "" { + contentType = "application/octet-stream" + } + + objectStat := ObjectInfo{ + ETag: md5sum, + Key: objectName, + Size: resp.ContentLength, + LastModified: date, + ContentType: contentType, + // Extract only the relevant header keys describing the object. + // following function filters out a list of standard set of keys + // which are not part of object metadata. + Metadata: extractObjMetadata(resp.Header), + } + + // do not close body here, caller will close + return resp.Body, objectStat, nil +} diff --git a/vendor/github.com/minio/minio-go/api-get-options.go b/vendor/github.com/minio/minio-go/api-get-options.go new file mode 100644 index 0000000000000..dbf062d612a10 --- /dev/null +++ b/vendor/github.com/minio/minio-go/api-get-options.go @@ -0,0 +1,128 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2015-2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package minio + +import ( + "fmt" + "net/http" + "time" + + "github.com/minio/minio-go/pkg/encrypt" +) + +// GetObjectOptions are used to specify additional headers or options +// during GET requests. +type GetObjectOptions struct { + headers map[string]string + ServerSideEncryption encrypt.ServerSide +} + +// StatObjectOptions are used to specify additional headers or options +// during GET info/stat requests. +type StatObjectOptions struct { + GetObjectOptions +} + +// Header returns the http.Header representation of the GET options. +func (o GetObjectOptions) Header() http.Header { + headers := make(http.Header, len(o.headers)) + for k, v := range o.headers { + headers.Set(k, v) + } + if o.ServerSideEncryption != nil && o.ServerSideEncryption.Type() == encrypt.SSEC { + o.ServerSideEncryption.Marshal(headers) + } + return headers +} + +// Set adds a key value pair to the options. The +// key-value pair will be part of the HTTP GET request +// headers. +func (o *GetObjectOptions) Set(key, value string) { + if o.headers == nil { + o.headers = make(map[string]string) + } + o.headers[http.CanonicalHeaderKey(key)] = value +} + +// SetMatchETag - set match etag. +func (o *GetObjectOptions) SetMatchETag(etag string) error { + if etag == "" { + return ErrInvalidArgument("ETag cannot be empty.") + } + o.Set("If-Match", "\""+etag+"\"") + return nil +} + +// SetMatchETagExcept - set match etag except. +func (o *GetObjectOptions) SetMatchETagExcept(etag string) error { + if etag == "" { + return ErrInvalidArgument("ETag cannot be empty.") + } + o.Set("If-None-Match", "\""+etag+"\"") + return nil +} + +// SetUnmodified - set unmodified time since. +func (o *GetObjectOptions) SetUnmodified(modTime time.Time) error { + if modTime.IsZero() { + return ErrInvalidArgument("Modified since cannot be empty.") + } + o.Set("If-Unmodified-Since", modTime.Format(http.TimeFormat)) + return nil +} + +// SetModified - set modified time since. +func (o *GetObjectOptions) SetModified(modTime time.Time) error { + if modTime.IsZero() { + return ErrInvalidArgument("Modified since cannot be empty.") + } + o.Set("If-Modified-Since", modTime.Format(http.TimeFormat)) + return nil +} + +// SetRange - set the start and end offset of the object to be read. +// See https://tools.ietf.org/html/rfc7233#section-3.1 for reference. +func (o *GetObjectOptions) SetRange(start, end int64) error { + switch { + case start == 0 && end < 0: + // Read last '-end' bytes. `bytes=-N`. + o.Set("Range", fmt.Sprintf("bytes=%d", end)) + case 0 < start && end == 0: + // Read everything starting from offset + // 'start'. `bytes=N-`. + o.Set("Range", fmt.Sprintf("bytes=%d-", start)) + case 0 <= start && start <= end: + // Read everything starting at 'start' till the + // 'end'. `bytes=N-M` + o.Set("Range", fmt.Sprintf("bytes=%d-%d", start, end)) + default: + // All other cases such as + // bytes=-3- + // bytes=5-3 + // bytes=-2-4 + // bytes=-3-0 + // bytes=-3--2 + // are invalid. + return ErrInvalidArgument( + fmt.Sprintf( + "Invalid range specified: start=%d end=%d", + start, end)) + } + return nil +} diff --git a/vendor/github.com/minio/minio-go/api-get-policy.go b/vendor/github.com/minio/minio-go/api-get-policy.go new file mode 100644 index 0000000000000..12d4c590e70ae --- /dev/null +++ b/vendor/github.com/minio/minio-go/api-get-policy.go @@ -0,0 +1,78 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2015-2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package minio + +import ( + "context" + "io/ioutil" + "net/http" + "net/url" + + "github.com/minio/minio-go/pkg/s3utils" +) + +// GetBucketPolicy - get bucket policy at a given path. +func (c Client) GetBucketPolicy(bucketName string) (string, error) { + // Input validation. + if err := s3utils.CheckValidBucketName(bucketName); err != nil { + return "", err + } + bucketPolicy, err := c.getBucketPolicy(bucketName) + if err != nil { + errResponse := ToErrorResponse(err) + if errResponse.Code == "NoSuchBucketPolicy" { + return "", nil + } + return "", err + } + return bucketPolicy, nil +} + +// Request server for current bucket policy. +func (c Client) getBucketPolicy(bucketName string) (string, error) { + // Get resources properly escaped and lined up before + // using them in http request. + urlValues := make(url.Values) + urlValues.Set("policy", "") + + // Execute GET on bucket to list objects. + resp, err := c.executeMethod(context.Background(), "GET", requestMetadata{ + bucketName: bucketName, + queryValues: urlValues, + contentSHA256Hex: emptySHA256Hex, + }) + + defer closeResponse(resp) + if err != nil { + return "", err + } + + if resp != nil { + if resp.StatusCode != http.StatusOK { + return "", httpRespToErrorResponse(resp, bucketName, "") + } + } + + bucketPolicyBuf, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", err + } + + policy := string(bucketPolicyBuf) + return policy, err +} diff --git a/vendor/github.com/minio/minio-go/api-list.go b/vendor/github.com/minio/minio-go/api-list.go new file mode 100644 index 0000000000000..2f1350a34cb3d --- /dev/null +++ b/vendor/github.com/minio/minio-go/api-list.go @@ -0,0 +1,715 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2015-2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package minio + +import ( + "context" + "errors" + "fmt" + "net/http" + "net/url" + "strings" + + "github.com/minio/minio-go/pkg/s3utils" +) + +// ListBuckets list all buckets owned by this authenticated user. +// +// This call requires explicit authentication, no anonymous requests are +// allowed for listing buckets. +// +// api := client.New(....) +// for message := range api.ListBuckets() { +// fmt.Println(message) +// } +// +func (c Client) ListBuckets() ([]BucketInfo, error) { + // Execute GET on service. + resp, err := c.executeMethod(context.Background(), "GET", requestMetadata{contentSHA256Hex: emptySHA256Hex}) + defer closeResponse(resp) + if err != nil { + return nil, err + } + if resp != nil { + if resp.StatusCode != http.StatusOK { + return nil, httpRespToErrorResponse(resp, "", "") + } + } + listAllMyBucketsResult := listAllMyBucketsResult{} + err = xmlDecoder(resp.Body, &listAllMyBucketsResult) + if err != nil { + return nil, err + } + return listAllMyBucketsResult.Buckets.Bucket, nil +} + +/// Bucket Read Operations. + +// ListObjectsV2 lists all objects matching the objectPrefix from +// the specified bucket. If recursion is enabled it would list +// all subdirectories and all its contents. +// +// Your input parameters are just bucketName, objectPrefix, recursive +// and a done channel for pro-actively closing the internal go +// routine. If you enable recursive as 'true' this function will +// return back all the objects in a given bucket name and object +// prefix. +// +// api := client.New(....) +// // Create a done channel. +// doneCh := make(chan struct{}) +// defer close(doneCh) +// // Recursively list all objects in 'mytestbucket' +// recursive := true +// for message := range api.ListObjectsV2("mytestbucket", "starthere", recursive, doneCh) { +// fmt.Println(message) +// } +// +func (c Client) ListObjectsV2(bucketName, objectPrefix string, recursive bool, doneCh <-chan struct{}) <-chan ObjectInfo { + // Allocate new list objects channel. + objectStatCh := make(chan ObjectInfo, 1) + // Default listing is delimited at "/" + delimiter := "/" + if recursive { + // If recursive we do not delimit. + delimiter = "" + } + + // Return object owner information by default + fetchOwner := true + + // Validate bucket name. + if err := s3utils.CheckValidBucketName(bucketName); err != nil { + defer close(objectStatCh) + objectStatCh <- ObjectInfo{ + Err: err, + } + return objectStatCh + } + + // Validate incoming object prefix. + if err := s3utils.CheckValidObjectNamePrefix(objectPrefix); err != nil { + defer close(objectStatCh) + objectStatCh <- ObjectInfo{ + Err: err, + } + return objectStatCh + } + + // Initiate list objects goroutine here. + go func(objectStatCh chan<- ObjectInfo) { + defer close(objectStatCh) + // Save continuationToken for next request. + var continuationToken string + for { + // Get list of objects a maximum of 1000 per request. + result, err := c.listObjectsV2Query(bucketName, objectPrefix, continuationToken, fetchOwner, delimiter, 1000, "") + if err != nil { + objectStatCh <- ObjectInfo{ + Err: err, + } + return + } + + // If contents are available loop through and send over channel. + for _, object := range result.Contents { + select { + // Send object content. + case objectStatCh <- object: + // If receives done from the caller, return here. + case <-doneCh: + return + } + } + + // Send all common prefixes if any. + // NOTE: prefixes are only present if the request is delimited. + for _, obj := range result.CommonPrefixes { + select { + // Send object prefixes. + case objectStatCh <- ObjectInfo{ + Key: obj.Prefix, + Size: 0, + }: + // If receives done from the caller, return here. + case <-doneCh: + return + } + } + + // If continuation token present, save it for next request. + if result.NextContinuationToken != "" { + continuationToken = result.NextContinuationToken + } + + // Listing ends result is not truncated, return right here. + if !result.IsTruncated { + return + } + } + }(objectStatCh) + return objectStatCh +} + +// listObjectsV2Query - (List Objects V2) - List some or all (up to 1000) of the objects in a bucket. +// +// You can use the request parameters as selection criteria to return a subset of the objects in a bucket. +// request parameters :- +// --------- +// ?continuation-token - Used to continue iterating over a set of objects +// ?delimiter - A delimiter is a character you use to group keys. +// ?prefix - Limits the response to keys that begin with the specified prefix. +// ?max-keys - Sets the maximum number of keys returned in the response body. +// ?start-after - Specifies the key to start after when listing objects in a bucket. +func (c Client) listObjectsV2Query(bucketName, objectPrefix, continuationToken string, fetchOwner bool, delimiter string, maxkeys int, startAfter string) (ListBucketV2Result, error) { + // Validate bucket name. + if err := s3utils.CheckValidBucketName(bucketName); err != nil { + return ListBucketV2Result{}, err + } + // Validate object prefix. + if err := s3utils.CheckValidObjectNamePrefix(objectPrefix); err != nil { + return ListBucketV2Result{}, err + } + // Get resources properly escaped and lined up before + // using them in http request. + urlValues := make(url.Values) + + // Always set list-type in ListObjects V2 + urlValues.Set("list-type", "2") + + // Set object prefix, prefix value to be set to empty is okay. + urlValues.Set("prefix", objectPrefix) + + // Set delimiter, delimiter value to be set to empty is okay. + urlValues.Set("delimiter", delimiter) + + // Set continuation token + if continuationToken != "" { + urlValues.Set("continuation-token", continuationToken) + } + + // Fetch owner when listing + if fetchOwner { + urlValues.Set("fetch-owner", "true") + } + + // maxkeys should default to 1000 or less. + if maxkeys == 0 || maxkeys > 1000 { + maxkeys = 1000 + } + // Set max keys. + urlValues.Set("max-keys", fmt.Sprintf("%d", maxkeys)) + + // Set start-after + if startAfter != "" { + urlValues.Set("start-after", startAfter) + } + + // Execute GET on bucket to list objects. + resp, err := c.executeMethod(context.Background(), "GET", requestMetadata{ + bucketName: bucketName, + queryValues: urlValues, + contentSHA256Hex: emptySHA256Hex, + }) + defer closeResponse(resp) + if err != nil { + return ListBucketV2Result{}, err + } + if resp != nil { + if resp.StatusCode != http.StatusOK { + return ListBucketV2Result{}, httpRespToErrorResponse(resp, bucketName, "") + } + } + + // Decode listBuckets XML. + listBucketResult := ListBucketV2Result{} + if err = xmlDecoder(resp.Body, &listBucketResult); err != nil { + return listBucketResult, err + } + + // This is an additional verification check to make + // sure proper responses are received. + if listBucketResult.IsTruncated && listBucketResult.NextContinuationToken == "" { + return listBucketResult, errors.New("Truncated response should have continuation token set") + } + + // Success. + return listBucketResult, nil +} + +// ListObjects - (List Objects) - List some objects or all recursively. +// +// ListObjects lists all objects matching the objectPrefix from +// the specified bucket. If recursion is enabled it would list +// all subdirectories and all its contents. +// +// Your input parameters are just bucketName, objectPrefix, recursive +// and a done channel for pro-actively closing the internal go +// routine. If you enable recursive as 'true' this function will +// return back all the objects in a given bucket name and object +// prefix. +// +// api := client.New(....) +// // Create a done channel. +// doneCh := make(chan struct{}) +// defer close(doneCh) +// // Recurively list all objects in 'mytestbucket' +// recursive := true +// for message := range api.ListObjects("mytestbucket", "starthere", recursive, doneCh) { +// fmt.Println(message) +// } +// +func (c Client) ListObjects(bucketName, objectPrefix string, recursive bool, doneCh <-chan struct{}) <-chan ObjectInfo { + // Allocate new list objects channel. + objectStatCh := make(chan ObjectInfo, 1) + // Default listing is delimited at "/" + delimiter := "/" + if recursive { + // If recursive we do not delimit. + delimiter = "" + } + // Validate bucket name. + if err := s3utils.CheckValidBucketName(bucketName); err != nil { + defer close(objectStatCh) + objectStatCh <- ObjectInfo{ + Err: err, + } + return objectStatCh + } + // Validate incoming object prefix. + if err := s3utils.CheckValidObjectNamePrefix(objectPrefix); err != nil { + defer close(objectStatCh) + objectStatCh <- ObjectInfo{ + Err: err, + } + return objectStatCh + } + + // Initiate list objects goroutine here. + go func(objectStatCh chan<- ObjectInfo) { + defer close(objectStatCh) + // Save marker for next request. + var marker string + for { + // Get list of objects a maximum of 1000 per request. + result, err := c.listObjectsQuery(bucketName, objectPrefix, marker, delimiter, 1000) + if err != nil { + objectStatCh <- ObjectInfo{ + Err: err, + } + return + } + + // If contents are available loop through and send over channel. + for _, object := range result.Contents { + // Save the marker. + marker = object.Key + select { + // Send object content. + case objectStatCh <- object: + // If receives done from the caller, return here. + case <-doneCh: + return + } + } + + // Send all common prefixes if any. + // NOTE: prefixes are only present if the request is delimited. + for _, obj := range result.CommonPrefixes { + object := ObjectInfo{} + object.Key = obj.Prefix + object.Size = 0 + select { + // Send object prefixes. + case objectStatCh <- object: + // If receives done from the caller, return here. + case <-doneCh: + return + } + } + + // If next marker present, save it for next request. + if result.NextMarker != "" { + marker = result.NextMarker + } + + // Listing ends result is not truncated, return right here. + if !result.IsTruncated { + return + } + } + }(objectStatCh) + return objectStatCh +} + +// listObjects - (List Objects) - List some or all (up to 1000) of the objects in a bucket. +// +// You can use the request parameters as selection criteria to return a subset of the objects in a bucket. +// request parameters :- +// --------- +// ?marker - Specifies the key to start with when listing objects in a bucket. +// ?delimiter - A delimiter is a character you use to group keys. +// ?prefix - Limits the response to keys that begin with the specified prefix. +// ?max-keys - Sets the maximum number of keys returned in the response body. +func (c Client) listObjectsQuery(bucketName, objectPrefix, objectMarker, delimiter string, maxkeys int) (ListBucketResult, error) { + // Validate bucket name. + if err := s3utils.CheckValidBucketName(bucketName); err != nil { + return ListBucketResult{}, err + } + // Validate object prefix. + if err := s3utils.CheckValidObjectNamePrefix(objectPrefix); err != nil { + return ListBucketResult{}, err + } + // Get resources properly escaped and lined up before + // using them in http request. + urlValues := make(url.Values) + + // Set object prefix, prefix value to be set to empty is okay. + urlValues.Set("prefix", objectPrefix) + + // Set delimiter, delimiter value to be set to empty is okay. + urlValues.Set("delimiter", delimiter) + + // Set object marker. + if objectMarker != "" { + urlValues.Set("marker", objectMarker) + } + + // maxkeys should default to 1000 or less. + if maxkeys == 0 || maxkeys > 1000 { + maxkeys = 1000 + } + // Set max keys. + urlValues.Set("max-keys", fmt.Sprintf("%d", maxkeys)) + + // Execute GET on bucket to list objects. + resp, err := c.executeMethod(context.Background(), "GET", requestMetadata{ + bucketName: bucketName, + queryValues: urlValues, + contentSHA256Hex: emptySHA256Hex, + }) + defer closeResponse(resp) + if err != nil { + return ListBucketResult{}, err + } + if resp != nil { + if resp.StatusCode != http.StatusOK { + return ListBucketResult{}, httpRespToErrorResponse(resp, bucketName, "") + } + } + // Decode listBuckets XML. + listBucketResult := ListBucketResult{} + err = xmlDecoder(resp.Body, &listBucketResult) + if err != nil { + return listBucketResult, err + } + return listBucketResult, nil +} + +// ListIncompleteUploads - List incompletely uploaded multipart objects. +// +// ListIncompleteUploads lists all incompleted objects matching the +// objectPrefix from the specified bucket. If recursion is enabled +// it would list all subdirectories and all its contents. +// +// Your input parameters are just bucketName, objectPrefix, recursive +// and a done channel to pro-actively close the internal go routine. +// If you enable recursive as 'true' this function will return back all +// the multipart objects in a given bucket name. +// +// api := client.New(....) +// // Create a done channel. +// doneCh := make(chan struct{}) +// defer close(doneCh) +// // Recurively list all objects in 'mytestbucket' +// recursive := true +// for message := range api.ListIncompleteUploads("mytestbucket", "starthere", recursive) { +// fmt.Println(message) +// } +// +func (c Client) ListIncompleteUploads(bucketName, objectPrefix string, recursive bool, doneCh <-chan struct{}) <-chan ObjectMultipartInfo { + // Turn on size aggregation of individual parts. + isAggregateSize := true + return c.listIncompleteUploads(bucketName, objectPrefix, recursive, isAggregateSize, doneCh) +} + +// listIncompleteUploads lists all incomplete uploads. +func (c Client) listIncompleteUploads(bucketName, objectPrefix string, recursive, aggregateSize bool, doneCh <-chan struct{}) <-chan ObjectMultipartInfo { + // Allocate channel for multipart uploads. + objectMultipartStatCh := make(chan ObjectMultipartInfo, 1) + // Delimiter is set to "/" by default. + delimiter := "/" + if recursive { + // If recursive do not delimit. + delimiter = "" + } + // Validate bucket name. + if err := s3utils.CheckValidBucketName(bucketName); err != nil { + defer close(objectMultipartStatCh) + objectMultipartStatCh <- ObjectMultipartInfo{ + Err: err, + } + return objectMultipartStatCh + } + // Validate incoming object prefix. + if err := s3utils.CheckValidObjectNamePrefix(objectPrefix); err != nil { + defer close(objectMultipartStatCh) + objectMultipartStatCh <- ObjectMultipartInfo{ + Err: err, + } + return objectMultipartStatCh + } + go func(objectMultipartStatCh chan<- ObjectMultipartInfo) { + defer close(objectMultipartStatCh) + // object and upload ID marker for future requests. + var objectMarker string + var uploadIDMarker string + for { + // list all multipart uploads. + result, err := c.listMultipartUploadsQuery(bucketName, objectMarker, uploadIDMarker, objectPrefix, delimiter, 1000) + if err != nil { + objectMultipartStatCh <- ObjectMultipartInfo{ + Err: err, + } + return + } + // Save objectMarker and uploadIDMarker for next request. + objectMarker = result.NextKeyMarker + uploadIDMarker = result.NextUploadIDMarker + // Send all multipart uploads. + for _, obj := range result.Uploads { + // Calculate total size of the uploaded parts if 'aggregateSize' is enabled. + if aggregateSize { + // Get total multipart size. + obj.Size, err = c.getTotalMultipartSize(bucketName, obj.Key, obj.UploadID) + if err != nil { + objectMultipartStatCh <- ObjectMultipartInfo{ + Err: err, + } + continue + } + } + select { + // Send individual uploads here. + case objectMultipartStatCh <- obj: + // If done channel return here. + case <-doneCh: + return + } + } + // Send all common prefixes if any. + // NOTE: prefixes are only present if the request is delimited. + for _, obj := range result.CommonPrefixes { + object := ObjectMultipartInfo{} + object.Key = obj.Prefix + object.Size = 0 + select { + // Send delimited prefixes here. + case objectMultipartStatCh <- object: + // If done channel return here. + case <-doneCh: + return + } + } + // Listing ends if result not truncated, return right here. + if !result.IsTruncated { + return + } + } + }(objectMultipartStatCh) + // return. + return objectMultipartStatCh +} + +// listMultipartUploads - (List Multipart Uploads). +// - Lists some or all (up to 1000) in-progress multipart uploads in a bucket. +// +// You can use the request parameters as selection criteria to return a subset of the uploads in a bucket. +// request parameters. :- +// --------- +// ?key-marker - Specifies the multipart upload after which listing should begin. +// ?upload-id-marker - Together with key-marker specifies the multipart upload after which listing should begin. +// ?delimiter - A delimiter is a character you use to group keys. +// ?prefix - Limits the response to keys that begin with the specified prefix. +// ?max-uploads - Sets the maximum number of multipart uploads returned in the response body. +func (c Client) listMultipartUploadsQuery(bucketName, keyMarker, uploadIDMarker, prefix, delimiter string, maxUploads int) (ListMultipartUploadsResult, error) { + // Get resources properly escaped and lined up before using them in http request. + urlValues := make(url.Values) + // Set uploads. + urlValues.Set("uploads", "") + // Set object key marker. + if keyMarker != "" { + urlValues.Set("key-marker", keyMarker) + } + // Set upload id marker. + if uploadIDMarker != "" { + urlValues.Set("upload-id-marker", uploadIDMarker) + } + + // Set object prefix, prefix value to be set to empty is okay. + urlValues.Set("prefix", prefix) + + // Set delimiter, delimiter value to be set to empty is okay. + urlValues.Set("delimiter", delimiter) + + // maxUploads should be 1000 or less. + if maxUploads == 0 || maxUploads > 1000 { + maxUploads = 1000 + } + // Set max-uploads. + urlValues.Set("max-uploads", fmt.Sprintf("%d", maxUploads)) + + // Execute GET on bucketName to list multipart uploads. + resp, err := c.executeMethod(context.Background(), "GET", requestMetadata{ + bucketName: bucketName, + queryValues: urlValues, + contentSHA256Hex: emptySHA256Hex, + }) + defer closeResponse(resp) + if err != nil { + return ListMultipartUploadsResult{}, err + } + if resp != nil { + if resp.StatusCode != http.StatusOK { + return ListMultipartUploadsResult{}, httpRespToErrorResponse(resp, bucketName, "") + } + } + // Decode response body. + listMultipartUploadsResult := ListMultipartUploadsResult{} + err = xmlDecoder(resp.Body, &listMultipartUploadsResult) + if err != nil { + return listMultipartUploadsResult, err + } + return listMultipartUploadsResult, nil +} + +// listObjectParts list all object parts recursively. +func (c Client) listObjectParts(bucketName, objectName, uploadID string) (partsInfo map[int]ObjectPart, err error) { + // Part number marker for the next batch of request. + var nextPartNumberMarker int + partsInfo = make(map[int]ObjectPart) + for { + // Get list of uploaded parts a maximum of 1000 per request. + listObjPartsResult, err := c.listObjectPartsQuery(bucketName, objectName, uploadID, nextPartNumberMarker, 1000) + if err != nil { + return nil, err + } + // Append to parts info. + for _, part := range listObjPartsResult.ObjectParts { + // Trim off the odd double quotes from ETag in the beginning and end. + part.ETag = strings.TrimPrefix(part.ETag, "\"") + part.ETag = strings.TrimSuffix(part.ETag, "\"") + partsInfo[part.PartNumber] = part + } + // Keep part number marker, for the next iteration. + nextPartNumberMarker = listObjPartsResult.NextPartNumberMarker + // Listing ends result is not truncated, return right here. + if !listObjPartsResult.IsTruncated { + break + } + } + + // Return all the parts. + return partsInfo, nil +} + +// findUploadIDs lists all incomplete uploads and find the uploadIDs of the matching object name. +func (c Client) findUploadIDs(bucketName, objectName string) ([]string, error) { + var uploadIDs []string + // Make list incomplete uploads recursive. + isRecursive := true + // Turn off size aggregation of individual parts, in this request. + isAggregateSize := false + // Create done channel to cleanup the routine. + doneCh := make(chan struct{}) + defer close(doneCh) + // List all incomplete uploads. + for mpUpload := range c.listIncompleteUploads(bucketName, objectName, isRecursive, isAggregateSize, doneCh) { + if mpUpload.Err != nil { + return nil, mpUpload.Err + } + if objectName == mpUpload.Key { + uploadIDs = append(uploadIDs, mpUpload.UploadID) + } + } + // Return the latest upload id. + return uploadIDs, nil +} + +// getTotalMultipartSize - calculate total uploaded size for the a given multipart object. +func (c Client) getTotalMultipartSize(bucketName, objectName, uploadID string) (size int64, err error) { + // Iterate over all parts and aggregate the size. + partsInfo, err := c.listObjectParts(bucketName, objectName, uploadID) + if err != nil { + return 0, err + } + for _, partInfo := range partsInfo { + size += partInfo.Size + } + return size, nil +} + +// listObjectPartsQuery (List Parts query) +// - lists some or all (up to 1000) parts that have been uploaded +// for a specific multipart upload +// +// You can use the request parameters as selection criteria to return +// a subset of the uploads in a bucket, request parameters :- +// --------- +// ?part-number-marker - Specifies the part after which listing should +// begin. +// ?max-parts - Maximum parts to be listed per request. +func (c Client) listObjectPartsQuery(bucketName, objectName, uploadID string, partNumberMarker, maxParts int) (ListObjectPartsResult, error) { + // Get resources properly escaped and lined up before using them in http request. + urlValues := make(url.Values) + // Set part number marker. + urlValues.Set("part-number-marker", fmt.Sprintf("%d", partNumberMarker)) + // Set upload id. + urlValues.Set("uploadId", uploadID) + + // maxParts should be 1000 or less. + if maxParts == 0 || maxParts > 1000 { + maxParts = 1000 + } + // Set max parts. + urlValues.Set("max-parts", fmt.Sprintf("%d", maxParts)) + + // Execute GET on objectName to get list of parts. + resp, err := c.executeMethod(context.Background(), "GET", requestMetadata{ + bucketName: bucketName, + objectName: objectName, + queryValues: urlValues, + contentSHA256Hex: emptySHA256Hex, + }) + defer closeResponse(resp) + if err != nil { + return ListObjectPartsResult{}, err + } + if resp != nil { + if resp.StatusCode != http.StatusOK { + return ListObjectPartsResult{}, httpRespToErrorResponse(resp, bucketName, objectName) + } + } + // Decode list object parts XML. + listObjectPartsResult := ListObjectPartsResult{} + err = xmlDecoder(resp.Body, &listObjectPartsResult) + if err != nil { + return listObjectPartsResult, err + } + return listObjectPartsResult, nil +} diff --git a/vendor/github.com/minio/minio-go/api-notification.go b/vendor/github.com/minio/minio-go/api-notification.go new file mode 100644 index 0000000000000..1c01e362b96a5 --- /dev/null +++ b/vendor/github.com/minio/minio-go/api-notification.go @@ -0,0 +1,228 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package minio + +import ( + "bufio" + "context" + "encoding/json" + "io" + "net/http" + "net/url" + "time" + + "github.com/minio/minio-go/pkg/s3utils" +) + +// GetBucketNotification - get bucket notification at a given path. +func (c Client) GetBucketNotification(bucketName string) (bucketNotification BucketNotification, err error) { + // Input validation. + if err := s3utils.CheckValidBucketName(bucketName); err != nil { + return BucketNotification{}, err + } + notification, err := c.getBucketNotification(bucketName) + if err != nil { + return BucketNotification{}, err + } + return notification, nil +} + +// Request server for notification rules. +func (c Client) getBucketNotification(bucketName string) (BucketNotification, error) { + urlValues := make(url.Values) + urlValues.Set("notification", "") + + // Execute GET on bucket to list objects. + resp, err := c.executeMethod(context.Background(), "GET", requestMetadata{ + bucketName: bucketName, + queryValues: urlValues, + contentSHA256Hex: emptySHA256Hex, + }) + + defer closeResponse(resp) + if err != nil { + return BucketNotification{}, err + } + return processBucketNotificationResponse(bucketName, resp) + +} + +// processes the GetNotification http response from the server. +func processBucketNotificationResponse(bucketName string, resp *http.Response) (BucketNotification, error) { + if resp.StatusCode != http.StatusOK { + errResponse := httpRespToErrorResponse(resp, bucketName, "") + return BucketNotification{}, errResponse + } + var bucketNotification BucketNotification + err := xmlDecoder(resp.Body, &bucketNotification) + if err != nil { + return BucketNotification{}, err + } + return bucketNotification, nil +} + +// Indentity represents the user id, this is a compliance field. +type identity struct { + PrincipalID string `json:"principalId"` +} + +// Notification event bucket metadata. +type bucketMeta struct { + Name string `json:"name"` + OwnerIdentity identity `json:"ownerIdentity"` + ARN string `json:"arn"` +} + +// Notification event object metadata. +type objectMeta struct { + Key string `json:"key"` + Size int64 `json:"size,omitempty"` + ETag string `json:"eTag,omitempty"` + VersionID string `json:"versionId,omitempty"` + Sequencer string `json:"sequencer"` +} + +// Notification event server specific metadata. +type eventMeta struct { + SchemaVersion string `json:"s3SchemaVersion"` + ConfigurationID string `json:"configurationId"` + Bucket bucketMeta `json:"bucket"` + Object objectMeta `json:"object"` +} + +// sourceInfo represents information on the client that +// triggered the event notification. +type sourceInfo struct { + Host string `json:"host"` + Port string `json:"port"` + UserAgent string `json:"userAgent"` +} + +// NotificationEvent represents an Amazon an S3 bucket notification event. +type NotificationEvent struct { + EventVersion string `json:"eventVersion"` + EventSource string `json:"eventSource"` + AwsRegion string `json:"awsRegion"` + EventTime string `json:"eventTime"` + EventName string `json:"eventName"` + UserIdentity identity `json:"userIdentity"` + RequestParameters map[string]string `json:"requestParameters"` + ResponseElements map[string]string `json:"responseElements"` + S3 eventMeta `json:"s3"` + Source sourceInfo `json:"source"` +} + +// NotificationInfo - represents the collection of notification events, additionally +// also reports errors if any while listening on bucket notifications. +type NotificationInfo struct { + Records []NotificationEvent + Err error +} + +// ListenBucketNotification - listen on bucket notifications. +func (c Client) ListenBucketNotification(bucketName, prefix, suffix string, events []string, doneCh <-chan struct{}) <-chan NotificationInfo { + notificationInfoCh := make(chan NotificationInfo, 1) + // Only success, start a routine to start reading line by line. + go func(notificationInfoCh chan<- NotificationInfo) { + defer close(notificationInfoCh) + + // Validate the bucket name. + if err := s3utils.CheckValidBucketName(bucketName); err != nil { + notificationInfoCh <- NotificationInfo{ + Err: err, + } + return + } + + // Check ARN partition to verify if listening bucket is supported + if s3utils.IsAmazonEndpoint(*c.endpointURL) || s3utils.IsGoogleEndpoint(*c.endpointURL) { + notificationInfoCh <- NotificationInfo{ + Err: ErrAPINotSupported("Listening for bucket notification is specific only to `minio` server endpoints"), + } + return + } + + // Continuously run and listen on bucket notification. + // Create a done channel to control 'ListObjects' go routine. + retryDoneCh := make(chan struct{}, 1) + + // Indicate to our routine to exit cleanly upon return. + defer close(retryDoneCh) + + // Wait on the jitter retry loop. + for range c.newRetryTimerContinous(time.Second, time.Second*30, MaxJitter, retryDoneCh) { + urlValues := make(url.Values) + urlValues.Set("prefix", prefix) + urlValues.Set("suffix", suffix) + urlValues["events"] = events + + // Execute GET on bucket to list objects. + resp, err := c.executeMethod(context.Background(), "GET", requestMetadata{ + bucketName: bucketName, + queryValues: urlValues, + contentSHA256Hex: emptySHA256Hex, + }) + if err != nil { + notificationInfoCh <- NotificationInfo{ + Err: err, + } + return + } + + // Validate http response, upon error return quickly. + if resp.StatusCode != http.StatusOK { + errResponse := httpRespToErrorResponse(resp, bucketName, "") + notificationInfoCh <- NotificationInfo{ + Err: errResponse, + } + return + } + + // Initialize a new bufio scanner, to read line by line. + bio := bufio.NewScanner(resp.Body) + + // Close the response body. + defer resp.Body.Close() + + // Unmarshal each line, returns marshalled values. + for bio.Scan() { + var notificationInfo NotificationInfo + if err = json.Unmarshal(bio.Bytes(), ¬ificationInfo); err != nil { + continue + } + // Send notificationInfo + select { + case notificationInfoCh <- notificationInfo: + case <-doneCh: + return + } + } + // Look for any underlying errors. + if err = bio.Err(); err != nil { + // For an unexpected connection drop from server, we close the body + // and re-connect. + if err == io.ErrUnexpectedEOF { + resp.Body.Close() + } + } + } + }(notificationInfoCh) + + // Returns the notification info channel, for caller to start reading from. + return notificationInfoCh +} diff --git a/vendor/github.com/minio/minio-go/api-presigned.go b/vendor/github.com/minio/minio-go/api-presigned.go new file mode 100644 index 0000000000000..a2c06078684b6 --- /dev/null +++ b/vendor/github.com/minio/minio-go/api-presigned.go @@ -0,0 +1,215 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2015-2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package minio + +import ( + "errors" + "net/http" + "net/url" + "time" + + "github.com/minio/minio-go/pkg/s3signer" + "github.com/minio/minio-go/pkg/s3utils" +) + +// presignURL - Returns a presigned URL for an input 'method'. +// Expires maximum is 7days - ie. 604800 and minimum is 1. +func (c Client) presignURL(method string, bucketName string, objectName string, expires time.Duration, reqParams url.Values) (u *url.URL, err error) { + // Input validation. + if method == "" { + return nil, ErrInvalidArgument("method cannot be empty.") + } + if err = s3utils.CheckValidBucketName(bucketName); err != nil { + return nil, err + } + if err = isValidExpiry(expires); err != nil { + return nil, err + } + + // Convert expires into seconds. + expireSeconds := int64(expires / time.Second) + reqMetadata := requestMetadata{ + presignURL: true, + bucketName: bucketName, + objectName: objectName, + expires: expireSeconds, + queryValues: reqParams, + } + + // Instantiate a new request. + // Since expires is set newRequest will presign the request. + var req *http.Request + if req, err = c.newRequest(method, reqMetadata); err != nil { + return nil, err + } + return req.URL, nil +} + +// PresignedGetObject - Returns a presigned URL to access an object +// data without credentials. URL can have a maximum expiry of +// upto 7days or a minimum of 1sec. Additionally you can override +// a set of response headers using the query parameters. +func (c Client) PresignedGetObject(bucketName string, objectName string, expires time.Duration, reqParams url.Values) (u *url.URL, err error) { + if err = s3utils.CheckValidObjectName(objectName); err != nil { + return nil, err + } + return c.presignURL("GET", bucketName, objectName, expires, reqParams) +} + +// PresignedHeadObject - Returns a presigned URL to access object +// metadata without credentials. URL can have a maximum expiry of +// upto 7days or a minimum of 1sec. Additionally you can override +// a set of response headers using the query parameters. +func (c Client) PresignedHeadObject(bucketName string, objectName string, expires time.Duration, reqParams url.Values) (u *url.URL, err error) { + if err = s3utils.CheckValidObjectName(objectName); err != nil { + return nil, err + } + return c.presignURL("HEAD", bucketName, objectName, expires, reqParams) +} + +// PresignedPutObject - Returns a presigned URL to upload an object +// without credentials. URL can have a maximum expiry of upto 7days +// or a minimum of 1sec. +func (c Client) PresignedPutObject(bucketName string, objectName string, expires time.Duration) (u *url.URL, err error) { + if err = s3utils.CheckValidObjectName(objectName); err != nil { + return nil, err + } + return c.presignURL("PUT", bucketName, objectName, expires, nil) +} + +// Presign - returns a presigned URL for any http method of your choice +// along with custom request params. URL can have a maximum expiry of +// upto 7days or a minimum of 1sec. +func (c Client) Presign(method string, bucketName string, objectName string, expires time.Duration, reqParams url.Values) (u *url.URL, err error) { + return c.presignURL(method, bucketName, objectName, expires, reqParams) +} + +// PresignedPostPolicy - Returns POST urlString, form data to upload an object. +func (c Client) PresignedPostPolicy(p *PostPolicy) (u *url.URL, formData map[string]string, err error) { + // Validate input arguments. + if p.expiration.IsZero() { + return nil, nil, errors.New("Expiration time must be specified") + } + if _, ok := p.formData["key"]; !ok { + return nil, nil, errors.New("object key must be specified") + } + if _, ok := p.formData["bucket"]; !ok { + return nil, nil, errors.New("bucket name must be specified") + } + + bucketName := p.formData["bucket"] + // Fetch the bucket location. + location, err := c.getBucketLocation(bucketName) + if err != nil { + return nil, nil, err + } + + isVirtualHost := c.isVirtualHostStyleRequest(*c.endpointURL, bucketName) + + u, err = c.makeTargetURL(bucketName, "", location, isVirtualHost, nil) + if err != nil { + return nil, nil, err + } + + // Get credentials from the configured credentials provider. + credValues, err := c.credsProvider.Get() + if err != nil { + return nil, nil, err + } + + var ( + signerType = credValues.SignerType + sessionToken = credValues.SessionToken + accessKeyID = credValues.AccessKeyID + secretAccessKey = credValues.SecretAccessKey + ) + + if signerType.IsAnonymous() { + return nil, nil, ErrInvalidArgument("Presigned operations are not supported for anonymous credentials") + } + + // Keep time. + t := time.Now().UTC() + // For signature version '2' handle here. + if signerType.IsV2() { + policyBase64 := p.base64() + p.formData["policy"] = policyBase64 + // For Google endpoint set this value to be 'GoogleAccessId'. + if s3utils.IsGoogleEndpoint(*c.endpointURL) { + p.formData["GoogleAccessId"] = accessKeyID + } else { + // For all other endpoints set this value to be 'AWSAccessKeyId'. + p.formData["AWSAccessKeyId"] = accessKeyID + } + // Sign the policy. + p.formData["signature"] = s3signer.PostPresignSignatureV2(policyBase64, secretAccessKey) + return u, p.formData, nil + } + + // Add date policy. + if err = p.addNewPolicy(policyCondition{ + matchType: "eq", + condition: "$x-amz-date", + value: t.Format(iso8601DateFormat), + }); err != nil { + return nil, nil, err + } + + // Add algorithm policy. + if err = p.addNewPolicy(policyCondition{ + matchType: "eq", + condition: "$x-amz-algorithm", + value: signV4Algorithm, + }); err != nil { + return nil, nil, err + } + + // Add a credential policy. + credential := s3signer.GetCredential(accessKeyID, location, t) + if err = p.addNewPolicy(policyCondition{ + matchType: "eq", + condition: "$x-amz-credential", + value: credential, + }); err != nil { + return nil, nil, err + } + + if sessionToken != "" { + if err = p.addNewPolicy(policyCondition{ + matchType: "eq", + condition: "$x-amz-security-token", + value: sessionToken, + }); err != nil { + return nil, nil, err + } + } + + // Get base64 encoded policy. + policyBase64 := p.base64() + + // Fill in the form data. + p.formData["policy"] = policyBase64 + p.formData["x-amz-algorithm"] = signV4Algorithm + p.formData["x-amz-credential"] = credential + p.formData["x-amz-date"] = t.Format(iso8601DateFormat) + if sessionToken != "" { + p.formData["x-amz-security-token"] = sessionToken + } + p.formData["x-amz-signature"] = s3signer.PostPresignSignatureV4(policyBase64, t, secretAccessKey, location) + return u, p.formData, nil +} diff --git a/vendor/github.com/minio/minio-go/api-put-bucket.go b/vendor/github.com/minio/minio-go/api-put-bucket.go new file mode 100644 index 0000000000000..33dc0cf3d100c --- /dev/null +++ b/vendor/github.com/minio/minio-go/api-put-bucket.go @@ -0,0 +1,306 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2015-2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package minio + +import ( + "bytes" + "context" + "encoding/xml" + "io/ioutil" + "net/http" + "net/url" + "strings" + + "github.com/minio/minio-go/pkg/s3utils" +) + +/// Bucket operations + +// MakeBucket creates a new bucket with bucketName. +// +// Location is an optional argument, by default all buckets are +// created in US Standard Region. +// +// For Amazon S3 for more supported regions - http://docs.aws.amazon.com/general/latest/gr/rande.html +// For Google Cloud Storage for more supported regions - https://cloud.google.com/storage/docs/bucket-locations +func (c Client) MakeBucket(bucketName string, location string) (err error) { + defer func() { + // Save the location into cache on a successful makeBucket response. + if err == nil { + c.bucketLocCache.Set(bucketName, location) + } + }() + + // Validate the input arguments. + if err := s3utils.CheckValidBucketNameStrict(bucketName); err != nil { + return err + } + + // If location is empty, treat is a default region 'us-east-1'. + if location == "" { + location = "us-east-1" + // For custom region clients, default + // to custom region instead not 'us-east-1'. + if c.region != "" { + location = c.region + } + } + // PUT bucket request metadata. + reqMetadata := requestMetadata{ + bucketName: bucketName, + bucketLocation: location, + } + + // If location is not 'us-east-1' create bucket location config. + if location != "us-east-1" && location != "" { + createBucketConfig := createBucketConfiguration{} + createBucketConfig.Location = location + var createBucketConfigBytes []byte + createBucketConfigBytes, err = xml.Marshal(createBucketConfig) + if err != nil { + return err + } + reqMetadata.contentMD5Base64 = sumMD5Base64(createBucketConfigBytes) + reqMetadata.contentSHA256Hex = sum256Hex(createBucketConfigBytes) + reqMetadata.contentBody = bytes.NewReader(createBucketConfigBytes) + reqMetadata.contentLength = int64(len(createBucketConfigBytes)) + } + + // Execute PUT to create a new bucket. + resp, err := c.executeMethod(context.Background(), "PUT", reqMetadata) + defer closeResponse(resp) + if err != nil { + return err + } + + if resp != nil { + if resp.StatusCode != http.StatusOK { + return httpRespToErrorResponse(resp, bucketName, "") + } + } + + // Success. + return nil +} + +// SetBucketPolicy set the access permissions on an existing bucket. +func (c Client) SetBucketPolicy(bucketName, policy string) error { + // Input validation. + if err := s3utils.CheckValidBucketName(bucketName); err != nil { + return err + } + + // If policy is empty then delete the bucket policy. + if policy == "" { + return c.removeBucketPolicy(bucketName) + } + + // Save the updated policies. + return c.putBucketPolicy(bucketName, policy) +} + +// Saves a new bucket policy. +func (c Client) putBucketPolicy(bucketName, policy string) error { + // Input validation. + if err := s3utils.CheckValidBucketName(bucketName); err != nil { + return err + } + + // Get resources properly escaped and lined up before + // using them in http request. + urlValues := make(url.Values) + urlValues.Set("policy", "") + + // Content-length is mandatory for put policy request + policyReader := strings.NewReader(policy) + b, err := ioutil.ReadAll(policyReader) + if err != nil { + return err + } + + reqMetadata := requestMetadata{ + bucketName: bucketName, + queryValues: urlValues, + contentBody: policyReader, + contentLength: int64(len(b)), + } + + // Execute PUT to upload a new bucket policy. + resp, err := c.executeMethod(context.Background(), "PUT", reqMetadata) + defer closeResponse(resp) + if err != nil { + return err + } + if resp != nil { + if resp.StatusCode != http.StatusNoContent { + return httpRespToErrorResponse(resp, bucketName, "") + } + } + return nil +} + +// Removes all policies on a bucket. +func (c Client) removeBucketPolicy(bucketName string) error { + // Input validation. + if err := s3utils.CheckValidBucketName(bucketName); err != nil { + return err + } + // Get resources properly escaped and lined up before + // using them in http request. + urlValues := make(url.Values) + urlValues.Set("policy", "") + + // Execute DELETE on objectName. + resp, err := c.executeMethod(context.Background(), "DELETE", requestMetadata{ + bucketName: bucketName, + queryValues: urlValues, + contentSHA256Hex: emptySHA256Hex, + }) + defer closeResponse(resp) + if err != nil { + return err + } + return nil +} + +// SetBucketLifecycle set the lifecycle on an existing bucket. +func (c Client) SetBucketLifecycle(bucketName, lifecycle string) error { + // Input validation. + if err := s3utils.CheckValidBucketName(bucketName); err != nil { + return err + } + + // If lifecycle is empty then delete it. + if lifecycle == "" { + return c.removeBucketLifecycle(bucketName) + } + + // Save the updated lifecycle. + return c.putBucketLifecycle(bucketName, lifecycle) +} + +// Saves a new bucket lifecycle. +func (c Client) putBucketLifecycle(bucketName, lifecycle string) error { + // Input validation. + if err := s3utils.CheckValidBucketName(bucketName); err != nil { + return err + } + + // Get resources properly escaped and lined up before + // using them in http request. + urlValues := make(url.Values) + urlValues.Set("lifecycle", "") + + // Content-length is mandatory for put lifecycle request + lifecycleReader := strings.NewReader(lifecycle) + b, err := ioutil.ReadAll(lifecycleReader) + if err != nil { + return err + } + + reqMetadata := requestMetadata{ + bucketName: bucketName, + queryValues: urlValues, + contentBody: lifecycleReader, + contentLength: int64(len(b)), + contentMD5Base64: sumMD5Base64(b), + } + + // Execute PUT to upload a new bucket lifecycle. + resp, err := c.executeMethod(context.Background(), "PUT", reqMetadata) + defer closeResponse(resp) + if err != nil { + return err + } + if resp != nil { + if resp.StatusCode != http.StatusOK { + return httpRespToErrorResponse(resp, bucketName, "") + } + } + return nil +} + +// Remove lifecycle from a bucket. +func (c Client) removeBucketLifecycle(bucketName string) error { + // Input validation. + if err := s3utils.CheckValidBucketName(bucketName); err != nil { + return err + } + // Get resources properly escaped and lined up before + // using them in http request. + urlValues := make(url.Values) + urlValues.Set("lifecycle", "") + + // Execute DELETE on objectName. + resp, err := c.executeMethod(context.Background(), "DELETE", requestMetadata{ + bucketName: bucketName, + queryValues: urlValues, + contentSHA256Hex: emptySHA256Hex, + }) + defer closeResponse(resp) + if err != nil { + return err + } + return nil +} + +// SetBucketNotification saves a new bucket notification. +func (c Client) SetBucketNotification(bucketName string, bucketNotification BucketNotification) error { + // Input validation. + if err := s3utils.CheckValidBucketName(bucketName); err != nil { + return err + } + + // Get resources properly escaped and lined up before + // using them in http request. + urlValues := make(url.Values) + urlValues.Set("notification", "") + + notifBytes, err := xml.Marshal(bucketNotification) + if err != nil { + return err + } + + notifBuffer := bytes.NewReader(notifBytes) + reqMetadata := requestMetadata{ + bucketName: bucketName, + queryValues: urlValues, + contentBody: notifBuffer, + contentLength: int64(len(notifBytes)), + contentMD5Base64: sumMD5Base64(notifBytes), + contentSHA256Hex: sum256Hex(notifBytes), + } + + // Execute PUT to upload a new bucket notification. + resp, err := c.executeMethod(context.Background(), "PUT", reqMetadata) + defer closeResponse(resp) + if err != nil { + return err + } + if resp != nil { + if resp.StatusCode != http.StatusOK { + return httpRespToErrorResponse(resp, bucketName, "") + } + } + return nil +} + +// RemoveAllBucketNotification - Remove bucket notification clears all previously specified config +func (c Client) RemoveAllBucketNotification(bucketName string) error { + return c.SetBucketNotification(bucketName, BucketNotification{}) +} diff --git a/vendor/github.com/minio/minio-go/api-put-object-common.go b/vendor/github.com/minio/minio-go/api-put-object-common.go new file mode 100644 index 0000000000000..c16c3c69ae6c1 --- /dev/null +++ b/vendor/github.com/minio/minio-go/api-put-object-common.go @@ -0,0 +1,111 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2015-2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package minio + +import ( + "context" + "io" + "math" + "os" + + "github.com/minio/minio-go/pkg/s3utils" +) + +// Verify if reader is *minio.Object +func isObject(reader io.Reader) (ok bool) { + _, ok = reader.(*Object) + return +} + +// Verify if reader is a generic ReaderAt +func isReadAt(reader io.Reader) (ok bool) { + _, ok = reader.(io.ReaderAt) + if ok { + var v *os.File + v, ok = reader.(*os.File) + if ok { + // Stdin, Stdout and Stderr all have *os.File type + // which happen to also be io.ReaderAt compatible + // we need to add special conditions for them to + // be ignored by this function. + for _, f := range []string{ + "/dev/stdin", + "/dev/stdout", + "/dev/stderr", + } { + if f == v.Name() { + ok = false + break + } + } + } + } + return +} + +// optimalPartInfo - calculate the optimal part info for a given +// object size. +// +// NOTE: Assumption here is that for any object to be uploaded to any S3 compatible +// object storage it will have the following parameters as constants. +// +// maxPartsCount - 10000 +// minPartSize - 64MiB +// maxMultipartPutObjectSize - 5TiB +// +func optimalPartInfo(objectSize int64) (totalPartsCount int, partSize int64, lastPartSize int64, err error) { + // object size is '-1' set it to 5TiB. + if objectSize == -1 { + objectSize = maxMultipartPutObjectSize + } + // object size is larger than supported maximum. + if objectSize > maxMultipartPutObjectSize { + err = ErrEntityTooLarge(objectSize, maxMultipartPutObjectSize, "", "") + return + } + // Use floats for part size for all calculations to avoid + // overflows during float64 to int64 conversions. + partSizeFlt := math.Ceil(float64(objectSize / maxPartsCount)) + partSizeFlt = math.Ceil(partSizeFlt/minPartSize) * minPartSize + // Total parts count. + totalPartsCount = int(math.Ceil(float64(objectSize) / partSizeFlt)) + // Part size. + partSize = int64(partSizeFlt) + // Last part size. + lastPartSize = objectSize - int64(totalPartsCount-1)*partSize + return totalPartsCount, partSize, lastPartSize, nil +} + +// getUploadID - fetch upload id if already present for an object name +// or initiate a new request to fetch a new upload id. +func (c Client) newUploadID(ctx context.Context, bucketName, objectName string, opts PutObjectOptions) (uploadID string, err error) { + // Input validation. + if err := s3utils.CheckValidBucketName(bucketName); err != nil { + return "", err + } + if err := s3utils.CheckValidObjectName(objectName); err != nil { + return "", err + } + + // Initiate multipart upload for an object. + initMultipartUploadResult, err := c.initiateMultipartUpload(ctx, bucketName, objectName, opts) + if err != nil { + return "", err + } + return initMultipartUploadResult.UploadID, nil +} diff --git a/vendor/github.com/minio/minio-go/api-put-object-context.go b/vendor/github.com/minio/minio-go/api-put-object-context.go new file mode 100644 index 0000000000000..ff4663e2f6514 --- /dev/null +++ b/vendor/github.com/minio/minio-go/api-put-object-context.go @@ -0,0 +1,33 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package minio + +import ( + "context" + "io" +) + +// PutObjectWithContext - Identical to PutObject call, but accepts context to facilitate request cancellation. +func (c Client) PutObjectWithContext(ctx context.Context, bucketName, objectName string, reader io.Reader, objectSize int64, + opts PutObjectOptions) (n int64, err error) { + err = opts.validate() + if err != nil { + return 0, err + } + return c.putObjectCommon(ctx, bucketName, objectName, reader, objectSize, opts) +} diff --git a/vendor/github.com/minio/minio-go/api-put-object-copy.go b/vendor/github.com/minio/minio-go/api-put-object-copy.go new file mode 100644 index 0000000000000..21322ef6ae42e --- /dev/null +++ b/vendor/github.com/minio/minio-go/api-put-object-copy.go @@ -0,0 +1,83 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2017, 2018 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package minio + +import ( + "context" + "io" + "io/ioutil" + "net/http" + + "github.com/minio/minio-go/pkg/encrypt" +) + +// CopyObject - copy a source object into a new object +func (c Client) CopyObject(dst DestinationInfo, src SourceInfo) error { + return c.CopyObjectWithProgress(dst, src, nil) +} + +// CopyObjectWithProgress - copy a source object into a new object, optionally takes +// progress bar input to notify current progress. +func (c Client) CopyObjectWithProgress(dst DestinationInfo, src SourceInfo, progress io.Reader) error { + header := make(http.Header) + for k, v := range src.Headers { + header[k] = v + } + + var err error + var size int64 + // If progress bar is specified, size should be requested as well initiate a StatObject request. + if progress != nil { + size, _, _, err = src.getProps(c) + if err != nil { + return err + } + } + + if src.encryption != nil { + encrypt.SSECopy(src.encryption).Marshal(header) + } + + if dst.encryption != nil { + dst.encryption.Marshal(header) + } + for k, v := range dst.getUserMetaHeadersMap(true) { + header.Set(k, v) + } + + resp, err := c.executeMethod(context.Background(), "PUT", requestMetadata{ + bucketName: dst.bucket, + objectName: dst.object, + customHeader: header, + }) + if err != nil { + return err + } + defer closeResponse(resp) + + if resp.StatusCode != http.StatusOK { + return httpRespToErrorResponse(resp, dst.bucket, dst.object) + } + + // Update the progress properly after successful copy. + if progress != nil { + io.CopyN(ioutil.Discard, progress, size) + } + + return nil +} diff --git a/vendor/github.com/minio/minio-go/api-put-object-file-context.go b/vendor/github.com/minio/minio-go/api-put-object-file-context.go new file mode 100644 index 0000000000000..140a9c0697783 --- /dev/null +++ b/vendor/github.com/minio/minio-go/api-put-object-file-context.go @@ -0,0 +1,64 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package minio + +import ( + "context" + "mime" + "os" + "path/filepath" + + "github.com/minio/minio-go/pkg/s3utils" +) + +// FPutObjectWithContext - Create an object in a bucket, with contents from file at filePath. Allows request cancellation. +func (c Client) FPutObjectWithContext(ctx context.Context, bucketName, objectName, filePath string, opts PutObjectOptions) (n int64, err error) { + // Input validation. + if err := s3utils.CheckValidBucketName(bucketName); err != nil { + return 0, err + } + if err := s3utils.CheckValidObjectName(objectName); err != nil { + return 0, err + } + + // Open the referenced file. + fileReader, err := os.Open(filePath) + // If any error fail quickly here. + if err != nil { + return 0, err + } + defer fileReader.Close() + + // Save the file stat. + fileStat, err := fileReader.Stat() + if err != nil { + return 0, err + } + + // Save the file size. + fileSize := fileStat.Size() + + // Set contentType based on filepath extension if not given or default + // value of "application/octet-stream" if the extension has no associated type. + if opts.ContentType == "" { + if opts.ContentType = mime.TypeByExtension(filepath.Ext(filePath)); opts.ContentType == "" { + opts.ContentType = "application/octet-stream" + } + } + return c.PutObjectWithContext(ctx, bucketName, objectName, fileReader, fileSize, opts) +} diff --git a/vendor/github.com/minio/minio-go/api-put-object-file.go b/vendor/github.com/minio/minio-go/api-put-object-file.go new file mode 100644 index 0000000000000..7c8e051178437 --- /dev/null +++ b/vendor/github.com/minio/minio-go/api-put-object-file.go @@ -0,0 +1,27 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2015-2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package minio + +import ( + "context" +) + +// FPutObject - Create an object in a bucket, with contents from file at filePath +func (c Client) FPutObject(bucketName, objectName, filePath string, opts PutObjectOptions) (n int64, err error) { + return c.FPutObjectWithContext(context.Background(), bucketName, objectName, filePath, opts) +} diff --git a/vendor/github.com/minio/minio-go/api-put-object-multipart.go b/vendor/github.com/minio/minio-go/api-put-object-multipart.go new file mode 100644 index 0000000000000..db92520e8e19d --- /dev/null +++ b/vendor/github.com/minio/minio-go/api-put-object-multipart.go @@ -0,0 +1,372 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2015-2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package minio + +import ( + "bytes" + "context" + "encoding/base64" + "encoding/hex" + "encoding/xml" + "fmt" + "io" + "io/ioutil" + "net/http" + "net/url" + "runtime/debug" + "sort" + "strconv" + "strings" + + "github.com/minio/minio-go/pkg/encrypt" + "github.com/minio/minio-go/pkg/s3utils" +) + +func (c Client) putObjectMultipart(ctx context.Context, bucketName, objectName string, reader io.Reader, size int64, + opts PutObjectOptions) (n int64, err error) { + n, err = c.putObjectMultipartNoStream(ctx, bucketName, objectName, reader, opts) + if err != nil { + errResp := ToErrorResponse(err) + // Verify if multipart functionality is not available, if not + // fall back to single PutObject operation. + if errResp.Code == "AccessDenied" && strings.Contains(errResp.Message, "Access Denied") { + // Verify if size of reader is greater than '5GiB'. + if size > maxSinglePutObjectSize { + return 0, ErrEntityTooLarge(size, maxSinglePutObjectSize, bucketName, objectName) + } + // Fall back to uploading as single PutObject operation. + return c.putObjectNoChecksum(ctx, bucketName, objectName, reader, size, opts) + } + } + return n, err +} + +func (c Client) putObjectMultipartNoStream(ctx context.Context, bucketName, objectName string, reader io.Reader, opts PutObjectOptions) (n int64, err error) { + // Input validation. + if err = s3utils.CheckValidBucketName(bucketName); err != nil { + return 0, err + } + if err = s3utils.CheckValidObjectName(objectName); err != nil { + return 0, err + } + + // Total data read and written to server. should be equal to + // 'size' at the end of the call. + var totalUploadedSize int64 + + // Complete multipart upload. + var complMultipartUpload completeMultipartUpload + + // Calculate the optimal parts info for a given size. + totalPartsCount, partSize, _, err := optimalPartInfo(-1) + if err != nil { + return 0, err + } + + // Initiate a new multipart upload. + uploadID, err := c.newUploadID(ctx, bucketName, objectName, opts) + if err != nil { + return 0, err + } + + defer func() { + if err != nil { + c.abortMultipartUpload(ctx, bucketName, objectName, uploadID) + } + }() + + // Part number always starts with '1'. + partNumber := 1 + + // Initialize parts uploaded map. + partsInfo := make(map[int]ObjectPart) + + // Create a buffer. + buf := make([]byte, partSize) + defer debug.FreeOSMemory() + + for partNumber <= totalPartsCount { + // Choose hash algorithms to be calculated by hashCopyN, + // avoid sha256 with non-v4 signature request or + // HTTPS connection. + hashAlgos, hashSums := c.hashMaterials() + + length, rErr := io.ReadFull(reader, buf) + if rErr == io.EOF { + break + } + if rErr != nil && rErr != io.ErrUnexpectedEOF { + return 0, rErr + } + + // Calculates hash sums while copying partSize bytes into cw. + for k, v := range hashAlgos { + v.Write(buf[:length]) + hashSums[k] = v.Sum(nil) + } + + // Update progress reader appropriately to the latest offset + // as we read from the source. + rd := newHook(bytes.NewReader(buf[:length]), opts.Progress) + + // Checksums.. + var ( + md5Base64 string + sha256Hex string + ) + if hashSums["md5"] != nil { + md5Base64 = base64.StdEncoding.EncodeToString(hashSums["md5"]) + } + if hashSums["sha256"] != nil { + sha256Hex = hex.EncodeToString(hashSums["sha256"]) + } + + // Proceed to upload the part. + var objPart ObjectPart + objPart, err = c.uploadPart(ctx, bucketName, objectName, uploadID, rd, partNumber, + md5Base64, sha256Hex, int64(length), opts.ServerSideEncryption) + if err != nil { + return totalUploadedSize, err + } + + // Save successfully uploaded part metadata. + partsInfo[partNumber] = objPart + + // Save successfully uploaded size. + totalUploadedSize += int64(length) + + // Increment part number. + partNumber++ + + // For unknown size, Read EOF we break away. + // We do not have to upload till totalPartsCount. + if rErr == io.EOF { + break + } + } + + // Loop over total uploaded parts to save them in + // Parts array before completing the multipart request. + for i := 1; i < partNumber; i++ { + part, ok := partsInfo[i] + if !ok { + return 0, ErrInvalidArgument(fmt.Sprintf("Missing part number %d", i)) + } + complMultipartUpload.Parts = append(complMultipartUpload.Parts, CompletePart{ + ETag: part.ETag, + PartNumber: part.PartNumber, + }) + } + + // Sort all completed parts. + sort.Sort(completedParts(complMultipartUpload.Parts)) + if _, err = c.completeMultipartUpload(ctx, bucketName, objectName, uploadID, complMultipartUpload); err != nil { + return totalUploadedSize, err + } + + // Return final size. + return totalUploadedSize, nil +} + +// initiateMultipartUpload - Initiates a multipart upload and returns an upload ID. +func (c Client) initiateMultipartUpload(ctx context.Context, bucketName, objectName string, opts PutObjectOptions) (initiateMultipartUploadResult, error) { + // Input validation. + if err := s3utils.CheckValidBucketName(bucketName); err != nil { + return initiateMultipartUploadResult{}, err + } + if err := s3utils.CheckValidObjectName(objectName); err != nil { + return initiateMultipartUploadResult{}, err + } + + // Initialize url queries. + urlValues := make(url.Values) + urlValues.Set("uploads", "") + + // Set ContentType header. + customHeader := opts.Header() + + reqMetadata := requestMetadata{ + bucketName: bucketName, + objectName: objectName, + queryValues: urlValues, + customHeader: customHeader, + } + + // Execute POST on an objectName to initiate multipart upload. + resp, err := c.executeMethod(ctx, "POST", reqMetadata) + defer closeResponse(resp) + if err != nil { + return initiateMultipartUploadResult{}, err + } + if resp != nil { + if resp.StatusCode != http.StatusOK { + return initiateMultipartUploadResult{}, httpRespToErrorResponse(resp, bucketName, objectName) + } + } + // Decode xml for new multipart upload. + initiateMultipartUploadResult := initiateMultipartUploadResult{} + err = xmlDecoder(resp.Body, &initiateMultipartUploadResult) + if err != nil { + return initiateMultipartUploadResult, err + } + return initiateMultipartUploadResult, nil +} + +// uploadPart - Uploads a part in a multipart upload. +func (c Client) uploadPart(ctx context.Context, bucketName, objectName, uploadID string, reader io.Reader, + partNumber int, md5Base64, sha256Hex string, size int64, sse encrypt.ServerSide) (ObjectPart, error) { + // Input validation. + if err := s3utils.CheckValidBucketName(bucketName); err != nil { + return ObjectPart{}, err + } + if err := s3utils.CheckValidObjectName(objectName); err != nil { + return ObjectPart{}, err + } + if size > maxPartSize { + return ObjectPart{}, ErrEntityTooLarge(size, maxPartSize, bucketName, objectName) + } + if size <= -1 { + return ObjectPart{}, ErrEntityTooSmall(size, bucketName, objectName) + } + if partNumber <= 0 { + return ObjectPart{}, ErrInvalidArgument("Part number cannot be negative or equal to zero.") + } + if uploadID == "" { + return ObjectPart{}, ErrInvalidArgument("UploadID cannot be empty.") + } + + // Get resources properly escaped and lined up before using them in http request. + urlValues := make(url.Values) + // Set part number. + urlValues.Set("partNumber", strconv.Itoa(partNumber)) + // Set upload id. + urlValues.Set("uploadId", uploadID) + + // Set encryption headers, if any. + customHeader := make(http.Header) + // https://docs.aws.amazon.com/AmazonS3/latest/API/mpUploadUploadPart.html + // Server-side encryption is supported by the S3 Multipart Upload actions. + // Unless you are using a customer-provided encryption key, you don't need + // to specify the encryption parameters in each UploadPart request. + if sse != nil && sse.Type() == encrypt.SSEC { + sse.Marshal(customHeader) + } + + reqMetadata := requestMetadata{ + bucketName: bucketName, + objectName: objectName, + queryValues: urlValues, + customHeader: customHeader, + contentBody: reader, + contentLength: size, + contentMD5Base64: md5Base64, + contentSHA256Hex: sha256Hex, + } + + // Execute PUT on each part. + resp, err := c.executeMethod(ctx, "PUT", reqMetadata) + defer closeResponse(resp) + if err != nil { + return ObjectPart{}, err + } + if resp != nil { + if resp.StatusCode != http.StatusOK { + return ObjectPart{}, httpRespToErrorResponse(resp, bucketName, objectName) + } + } + // Once successfully uploaded, return completed part. + objPart := ObjectPart{} + objPart.Size = size + objPart.PartNumber = partNumber + // Trim off the odd double quotes from ETag in the beginning and end. + objPart.ETag = strings.TrimPrefix(resp.Header.Get("ETag"), "\"") + objPart.ETag = strings.TrimSuffix(objPart.ETag, "\"") + return objPart, nil +} + +// completeMultipartUpload - Completes a multipart upload by assembling previously uploaded parts. +func (c Client) completeMultipartUpload(ctx context.Context, bucketName, objectName, uploadID string, + complete completeMultipartUpload) (completeMultipartUploadResult, error) { + // Input validation. + if err := s3utils.CheckValidBucketName(bucketName); err != nil { + return completeMultipartUploadResult{}, err + } + if err := s3utils.CheckValidObjectName(objectName); err != nil { + return completeMultipartUploadResult{}, err + } + + // Initialize url queries. + urlValues := make(url.Values) + urlValues.Set("uploadId", uploadID) + // Marshal complete multipart body. + completeMultipartUploadBytes, err := xml.Marshal(complete) + if err != nil { + return completeMultipartUploadResult{}, err + } + + // Instantiate all the complete multipart buffer. + completeMultipartUploadBuffer := bytes.NewReader(completeMultipartUploadBytes) + reqMetadata := requestMetadata{ + bucketName: bucketName, + objectName: objectName, + queryValues: urlValues, + contentBody: completeMultipartUploadBuffer, + contentLength: int64(len(completeMultipartUploadBytes)), + contentSHA256Hex: sum256Hex(completeMultipartUploadBytes), + } + + // Execute POST to complete multipart upload for an objectName. + resp, err := c.executeMethod(ctx, "POST", reqMetadata) + defer closeResponse(resp) + if err != nil { + return completeMultipartUploadResult{}, err + } + if resp != nil { + if resp.StatusCode != http.StatusOK { + return completeMultipartUploadResult{}, httpRespToErrorResponse(resp, bucketName, objectName) + } + } + + // Read resp.Body into a []bytes to parse for Error response inside the body + var b []byte + b, err = ioutil.ReadAll(resp.Body) + if err != nil { + return completeMultipartUploadResult{}, err + } + // Decode completed multipart upload response on success. + completeMultipartUploadResult := completeMultipartUploadResult{} + err = xmlDecoder(bytes.NewReader(b), &completeMultipartUploadResult) + if err != nil { + // xml parsing failure due to presence an ill-formed xml fragment + return completeMultipartUploadResult, err + } else if completeMultipartUploadResult.Bucket == "" { + // xml's Decode method ignores well-formed xml that don't apply to the type of value supplied. + // In this case, it would leave completeMultipartUploadResult with the corresponding zero-values + // of the members. + + // Decode completed multipart upload response on failure + completeMultipartUploadErr := ErrorResponse{} + err = xmlDecoder(bytes.NewReader(b), &completeMultipartUploadErr) + if err != nil { + // xml parsing failure due to presence an ill-formed xml fragment + return completeMultipartUploadResult, err + } + return completeMultipartUploadResult, completeMultipartUploadErr + } + return completeMultipartUploadResult, nil +} diff --git a/vendor/github.com/minio/minio-go/api-put-object-streaming.go b/vendor/github.com/minio/minio-go/api-put-object-streaming.go new file mode 100644 index 0000000000000..211d1c23c9e53 --- /dev/null +++ b/vendor/github.com/minio/minio-go/api-put-object-streaming.go @@ -0,0 +1,417 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package minio + +import ( + "context" + "fmt" + "io" + "net/http" + "sort" + "strings" + + "github.com/minio/minio-go/pkg/s3utils" +) + +// putObjectMultipartStream - upload a large object using +// multipart upload and streaming signature for signing payload. +// Comprehensive put object operation involving multipart uploads. +// +// Following code handles these types of readers. +// +// - *minio.Object +// - Any reader which has a method 'ReadAt()' +// +func (c Client) putObjectMultipartStream(ctx context.Context, bucketName, objectName string, + reader io.Reader, size int64, opts PutObjectOptions) (n int64, err error) { + + if !isObject(reader) && isReadAt(reader) { + // Verify if the reader implements ReadAt and it is not a *minio.Object then we will use parallel uploader. + n, err = c.putObjectMultipartStreamFromReadAt(ctx, bucketName, objectName, reader.(io.ReaderAt), size, opts) + } else { + n, err = c.putObjectMultipartStreamNoChecksum(ctx, bucketName, objectName, reader, size, opts) + } + if err != nil { + errResp := ToErrorResponse(err) + // Verify if multipart functionality is not available, if not + // fall back to single PutObject operation. + if errResp.Code == "AccessDenied" && strings.Contains(errResp.Message, "Access Denied") { + // Verify if size of reader is greater than '5GiB'. + if size > maxSinglePutObjectSize { + return 0, ErrEntityTooLarge(size, maxSinglePutObjectSize, bucketName, objectName) + } + // Fall back to uploading as single PutObject operation. + return c.putObjectNoChecksum(ctx, bucketName, objectName, reader, size, opts) + } + } + return n, err +} + +// uploadedPartRes - the response received from a part upload. +type uploadedPartRes struct { + Error error // Any error encountered while uploading the part. + PartNum int // Number of the part uploaded. + Size int64 // Size of the part uploaded. + Part *ObjectPart +} + +type uploadPartReq struct { + PartNum int // Number of the part uploaded. + Part *ObjectPart // Size of the part uploaded. +} + +// putObjectMultipartFromReadAt - Uploads files bigger than 64MiB. +// Supports all readers which implements io.ReaderAt interface +// (ReadAt method). +// +// NOTE: This function is meant to be used for all readers which +// implement io.ReaderAt which allows us for resuming multipart +// uploads but reading at an offset, which would avoid re-read the +// data which was already uploaded. Internally this function uses +// temporary files for staging all the data, these temporary files are +// cleaned automatically when the caller i.e http client closes the +// stream after uploading all the contents successfully. +func (c Client) putObjectMultipartStreamFromReadAt(ctx context.Context, bucketName, objectName string, + reader io.ReaderAt, size int64, opts PutObjectOptions) (n int64, err error) { + // Input validation. + if err = s3utils.CheckValidBucketName(bucketName); err != nil { + return 0, err + } + if err = s3utils.CheckValidObjectName(objectName); err != nil { + return 0, err + } + + // Calculate the optimal parts info for a given size. + totalPartsCount, partSize, lastPartSize, err := optimalPartInfo(size) + if err != nil { + return 0, err + } + + // Initiate a new multipart upload. + uploadID, err := c.newUploadID(ctx, bucketName, objectName, opts) + if err != nil { + return 0, err + } + + // Aborts the multipart upload in progress, if the + // function returns any error, since we do not resume + // we should purge the parts which have been uploaded + // to relinquish storage space. + defer func() { + if err != nil { + c.abortMultipartUpload(ctx, bucketName, objectName, uploadID) + } + }() + + // Total data read and written to server. should be equal to 'size' at the end of the call. + var totalUploadedSize int64 + + // Complete multipart upload. + var complMultipartUpload completeMultipartUpload + + // Declare a channel that sends the next part number to be uploaded. + // Buffered to 10000 because thats the maximum number of parts allowed + // by S3. + uploadPartsCh := make(chan uploadPartReq, 10000) + + // Declare a channel that sends back the response of a part upload. + // Buffered to 10000 because thats the maximum number of parts allowed + // by S3. + uploadedPartsCh := make(chan uploadedPartRes, 10000) + + // Used for readability, lastPartNumber is always totalPartsCount. + lastPartNumber := totalPartsCount + + // Send each part number to the channel to be processed. + for p := 1; p <= totalPartsCount; p++ { + uploadPartsCh <- uploadPartReq{PartNum: p, Part: nil} + } + close(uploadPartsCh) + // Receive each part number from the channel allowing three parallel uploads. + for w := 1; w <= opts.getNumThreads(); w++ { + go func(partSize int64) { + // Each worker will draw from the part channel and upload in parallel. + for uploadReq := range uploadPartsCh { + + // If partNumber was not uploaded we calculate the missing + // part offset and size. For all other part numbers we + // calculate offset based on multiples of partSize. + readOffset := int64(uploadReq.PartNum-1) * partSize + + // As a special case if partNumber is lastPartNumber, we + // calculate the offset based on the last part size. + if uploadReq.PartNum == lastPartNumber { + readOffset = (size - lastPartSize) + partSize = lastPartSize + } + + // Get a section reader on a particular offset. + sectionReader := newHook(io.NewSectionReader(reader, readOffset, partSize), opts.Progress) + + // Proceed to upload the part. + var objPart ObjectPart + objPart, err = c.uploadPart(ctx, bucketName, objectName, uploadID, + sectionReader, uploadReq.PartNum, + "", "", partSize, opts.ServerSideEncryption) + if err != nil { + uploadedPartsCh <- uploadedPartRes{ + Size: 0, + Error: err, + } + // Exit the goroutine. + return + } + + // Save successfully uploaded part metadata. + uploadReq.Part = &objPart + + // Send successful part info through the channel. + uploadedPartsCh <- uploadedPartRes{ + Size: objPart.Size, + PartNum: uploadReq.PartNum, + Part: uploadReq.Part, + Error: nil, + } + } + }(partSize) + } + + // Gather the responses as they occur and update any + // progress bar. + for u := 1; u <= totalPartsCount; u++ { + uploadRes := <-uploadedPartsCh + if uploadRes.Error != nil { + return totalUploadedSize, uploadRes.Error + } + // Retrieve each uploaded part and store it to be completed. + // part, ok := partsInfo[uploadRes.PartNum] + part := uploadRes.Part + if part == nil { + return 0, ErrInvalidArgument(fmt.Sprintf("Missing part number %d", uploadRes.PartNum)) + } + // Update the totalUploadedSize. + totalUploadedSize += uploadRes.Size + // Store the parts to be completed in order. + complMultipartUpload.Parts = append(complMultipartUpload.Parts, CompletePart{ + ETag: part.ETag, + PartNumber: part.PartNumber, + }) + } + + // Verify if we uploaded all the data. + if totalUploadedSize != size { + return totalUploadedSize, ErrUnexpectedEOF(totalUploadedSize, size, bucketName, objectName) + } + + // Sort all completed parts. + sort.Sort(completedParts(complMultipartUpload.Parts)) + _, err = c.completeMultipartUpload(ctx, bucketName, objectName, uploadID, complMultipartUpload) + if err != nil { + return totalUploadedSize, err + } + + // Return final size. + return totalUploadedSize, nil +} + +func (c Client) putObjectMultipartStreamNoChecksum(ctx context.Context, bucketName, objectName string, + reader io.Reader, size int64, opts PutObjectOptions) (n int64, err error) { + // Input validation. + if err = s3utils.CheckValidBucketName(bucketName); err != nil { + return 0, err + } + if err = s3utils.CheckValidObjectName(objectName); err != nil { + return 0, err + } + + // Calculate the optimal parts info for a given size. + totalPartsCount, partSize, lastPartSize, err := optimalPartInfo(size) + if err != nil { + return 0, err + } + // Initiates a new multipart request + uploadID, err := c.newUploadID(ctx, bucketName, objectName, opts) + if err != nil { + return 0, err + } + + // Aborts the multipart upload if the function returns + // any error, since we do not resume we should purge + // the parts which have been uploaded to relinquish + // storage space. + defer func() { + if err != nil { + c.abortMultipartUpload(ctx, bucketName, objectName, uploadID) + } + }() + + // Total data read and written to server. should be equal to 'size' at the end of the call. + var totalUploadedSize int64 + + // Initialize parts uploaded map. + partsInfo := make(map[int]ObjectPart) + + // Part number always starts with '1'. + var partNumber int + for partNumber = 1; partNumber <= totalPartsCount; partNumber++ { + // Update progress reader appropriately to the latest offset + // as we read from the source. + hookReader := newHook(reader, opts.Progress) + + // Proceed to upload the part. + if partNumber == totalPartsCount { + partSize = lastPartSize + } + var objPart ObjectPart + objPart, err = c.uploadPart(ctx, bucketName, objectName, uploadID, + io.LimitReader(hookReader, partSize), + partNumber, "", "", partSize, opts.ServerSideEncryption) + if err != nil { + return totalUploadedSize, err + } + + // Save successfully uploaded part metadata. + partsInfo[partNumber] = objPart + + // Save successfully uploaded size. + totalUploadedSize += partSize + } + + // Verify if we uploaded all the data. + if size > 0 { + if totalUploadedSize != size { + return totalUploadedSize, ErrUnexpectedEOF(totalUploadedSize, size, bucketName, objectName) + } + } + + // Complete multipart upload. + var complMultipartUpload completeMultipartUpload + + // Loop over total uploaded parts to save them in + // Parts array before completing the multipart request. + for i := 1; i < partNumber; i++ { + part, ok := partsInfo[i] + if !ok { + return 0, ErrInvalidArgument(fmt.Sprintf("Missing part number %d", i)) + } + complMultipartUpload.Parts = append(complMultipartUpload.Parts, CompletePart{ + ETag: part.ETag, + PartNumber: part.PartNumber, + }) + } + + // Sort all completed parts. + sort.Sort(completedParts(complMultipartUpload.Parts)) + _, err = c.completeMultipartUpload(ctx, bucketName, objectName, uploadID, complMultipartUpload) + if err != nil { + return totalUploadedSize, err + } + + // Return final size. + return totalUploadedSize, nil +} + +// putObjectNoChecksum special function used Google Cloud Storage. This special function +// is used for Google Cloud Storage since Google's multipart API is not S3 compatible. +func (c Client) putObjectNoChecksum(ctx context.Context, bucketName, objectName string, reader io.Reader, size int64, opts PutObjectOptions) (n int64, err error) { + // Input validation. + if err := s3utils.CheckValidBucketName(bucketName); err != nil { + return 0, err + } + if err := s3utils.CheckValidObjectName(objectName); err != nil { + return 0, err + } + + // Size -1 is only supported on Google Cloud Storage, we error + // out in all other situations. + if size < 0 && !s3utils.IsGoogleEndpoint(*c.endpointURL) { + return 0, ErrEntityTooSmall(size, bucketName, objectName) + } + if size > 0 { + if isReadAt(reader) && !isObject(reader) { + seeker, _ := reader.(io.Seeker) + offset, err := seeker.Seek(0, io.SeekCurrent) + if err != nil { + return 0, ErrInvalidArgument(err.Error()) + } + reader = io.NewSectionReader(reader.(io.ReaderAt), offset, size) + } + } + + // Update progress reader appropriately to the latest offset as we + // read from the source. + readSeeker := newHook(reader, opts.Progress) + + // This function does not calculate sha256 and md5sum for payload. + // Execute put object. + st, err := c.putObjectDo(ctx, bucketName, objectName, readSeeker, "", "", size, opts) + if err != nil { + return 0, err + } + if st.Size != size { + return 0, ErrUnexpectedEOF(st.Size, size, bucketName, objectName) + } + return size, nil +} + +// putObjectDo - executes the put object http operation. +// NOTE: You must have WRITE permissions on a bucket to add an object to it. +func (c Client) putObjectDo(ctx context.Context, bucketName, objectName string, reader io.Reader, md5Base64, sha256Hex string, size int64, opts PutObjectOptions) (ObjectInfo, error) { + // Input validation. + if err := s3utils.CheckValidBucketName(bucketName); err != nil { + return ObjectInfo{}, err + } + if err := s3utils.CheckValidObjectName(objectName); err != nil { + return ObjectInfo{}, err + } + // Set headers. + customHeader := opts.Header() + + // Populate request metadata. + reqMetadata := requestMetadata{ + bucketName: bucketName, + objectName: objectName, + customHeader: customHeader, + contentBody: reader, + contentLength: size, + contentMD5Base64: md5Base64, + contentSHA256Hex: sha256Hex, + } + + // Execute PUT an objectName. + resp, err := c.executeMethod(ctx, "PUT", reqMetadata) + defer closeResponse(resp) + if err != nil { + return ObjectInfo{}, err + } + if resp != nil { + if resp.StatusCode != http.StatusOK { + return ObjectInfo{}, httpRespToErrorResponse(resp, bucketName, objectName) + } + } + + var objInfo ObjectInfo + // Trim off the odd double quotes from ETag in the beginning and end. + objInfo.ETag = strings.TrimPrefix(resp.Header.Get("ETag"), "\"") + objInfo.ETag = strings.TrimSuffix(objInfo.ETag, "\"") + // A success here means data was written to server successfully. + objInfo.Size = size + + // Return here. + return objInfo, nil +} diff --git a/vendor/github.com/minio/minio-go/api-put-object.go b/vendor/github.com/minio/minio-go/api-put-object.go new file mode 100644 index 0000000000000..0330cd99d9c50 --- /dev/null +++ b/vendor/github.com/minio/minio-go/api-put-object.go @@ -0,0 +1,267 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2015-2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package minio + +import ( + "bytes" + "context" + "fmt" + "io" + "net/http" + "runtime/debug" + "sort" + + "github.com/minio/minio-go/pkg/encrypt" + "github.com/minio/minio-go/pkg/s3utils" + "golang.org/x/net/http/httpguts" +) + +// PutObjectOptions represents options specified by user for PutObject call +type PutObjectOptions struct { + UserMetadata map[string]string + Progress io.Reader + ContentType string + ContentEncoding string + ContentDisposition string + ContentLanguage string + CacheControl string + ServerSideEncryption encrypt.ServerSide + NumThreads uint + StorageClass string + WebsiteRedirectLocation string +} + +// getNumThreads - gets the number of threads to be used in the multipart +// put object operation +func (opts PutObjectOptions) getNumThreads() (numThreads int) { + if opts.NumThreads > 0 { + numThreads = int(opts.NumThreads) + } else { + numThreads = totalWorkers + } + return +} + +// Header - constructs the headers from metadata entered by user in +// PutObjectOptions struct +func (opts PutObjectOptions) Header() (header http.Header) { + header = make(http.Header) + + if opts.ContentType != "" { + header["Content-Type"] = []string{opts.ContentType} + } else { + header["Content-Type"] = []string{"application/octet-stream"} + } + if opts.ContentEncoding != "" { + header["Content-Encoding"] = []string{opts.ContentEncoding} + } + if opts.ContentDisposition != "" { + header["Content-Disposition"] = []string{opts.ContentDisposition} + } + if opts.ContentLanguage != "" { + header["Content-Language"] = []string{opts.ContentLanguage} + } + if opts.CacheControl != "" { + header["Cache-Control"] = []string{opts.CacheControl} + } + if opts.ServerSideEncryption != nil { + opts.ServerSideEncryption.Marshal(header) + } + if opts.StorageClass != "" { + header[amzStorageClass] = []string{opts.StorageClass} + } + if opts.WebsiteRedirectLocation != "" { + header[amzWebsiteRedirectLocation] = []string{opts.WebsiteRedirectLocation} + } + for k, v := range opts.UserMetadata { + if !isAmzHeader(k) && !isStandardHeader(k) && !isStorageClassHeader(k) { + header["X-Amz-Meta-"+k] = []string{v} + } else { + header[k] = []string{v} + } + } + return +} + +// validate() checks if the UserMetadata map has standard headers or and raises an error if so. +func (opts PutObjectOptions) validate() (err error) { + for k, v := range opts.UserMetadata { + if !httpguts.ValidHeaderFieldName(k) || isStandardHeader(k) || isSSEHeader(k) || isStorageClassHeader(k) { + return ErrInvalidArgument(k + " unsupported user defined metadata name") + } + if !httpguts.ValidHeaderFieldValue(v) { + return ErrInvalidArgument(v + " unsupported user defined metadata value") + } + } + return nil +} + +// completedParts is a collection of parts sortable by their part numbers. +// used for sorting the uploaded parts before completing the multipart request. +type completedParts []CompletePart + +func (a completedParts) Len() int { return len(a) } +func (a completedParts) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a completedParts) Less(i, j int) bool { return a[i].PartNumber < a[j].PartNumber } + +// PutObject creates an object in a bucket. +// +// You must have WRITE permissions on a bucket to create an object. +// +// - For size smaller than 64MiB PutObject automatically does a +// single atomic Put operation. +// - For size larger than 64MiB PutObject automatically does a +// multipart Put operation. +// - For size input as -1 PutObject does a multipart Put operation +// until input stream reaches EOF. Maximum object size that can +// be uploaded through this operation will be 5TiB. +func (c Client) PutObject(bucketName, objectName string, reader io.Reader, objectSize int64, + opts PutObjectOptions) (n int64, err error) { + return c.PutObjectWithContext(context.Background(), bucketName, objectName, reader, objectSize, opts) +} + +func (c Client) putObjectCommon(ctx context.Context, bucketName, objectName string, reader io.Reader, size int64, opts PutObjectOptions) (n int64, err error) { + // Check for largest object size allowed. + if size > int64(maxMultipartPutObjectSize) { + return 0, ErrEntityTooLarge(size, maxMultipartPutObjectSize, bucketName, objectName) + } + + // NOTE: Streaming signature is not supported by GCS. + if s3utils.IsGoogleEndpoint(*c.endpointURL) { + // Do not compute MD5 for Google Cloud Storage. + return c.putObjectNoChecksum(ctx, bucketName, objectName, reader, size, opts) + } + + if c.overrideSignerType.IsV2() { + if size >= 0 && size < minPartSize { + return c.putObjectNoChecksum(ctx, bucketName, objectName, reader, size, opts) + } + return c.putObjectMultipart(ctx, bucketName, objectName, reader, size, opts) + } + if size < 0 { + return c.putObjectMultipartStreamNoLength(ctx, bucketName, objectName, reader, opts) + } + + if size < minPartSize { + return c.putObjectNoChecksum(ctx, bucketName, objectName, reader, size, opts) + } + // For all sizes greater than 64MiB do multipart. + return c.putObjectMultipartStream(ctx, bucketName, objectName, reader, size, opts) +} + +func (c Client) putObjectMultipartStreamNoLength(ctx context.Context, bucketName, objectName string, reader io.Reader, opts PutObjectOptions) (n int64, err error) { + // Input validation. + if err = s3utils.CheckValidBucketName(bucketName); err != nil { + return 0, err + } + if err = s3utils.CheckValidObjectName(objectName); err != nil { + return 0, err + } + + // Total data read and written to server. should be equal to + // 'size' at the end of the call. + var totalUploadedSize int64 + + // Complete multipart upload. + var complMultipartUpload completeMultipartUpload + + // Calculate the optimal parts info for a given size. + totalPartsCount, partSize, _, err := optimalPartInfo(-1) + if err != nil { + return 0, err + } + // Initiate a new multipart upload. + uploadID, err := c.newUploadID(ctx, bucketName, objectName, opts) + if err != nil { + return 0, err + } + + defer func() { + if err != nil { + c.abortMultipartUpload(ctx, bucketName, objectName, uploadID) + } + }() + + // Part number always starts with '1'. + partNumber := 1 + + // Initialize parts uploaded map. + partsInfo := make(map[int]ObjectPart) + + // Create a buffer. + buf := make([]byte, partSize) + defer debug.FreeOSMemory() + + for partNumber <= totalPartsCount { + length, rErr := io.ReadFull(reader, buf) + if rErr == io.EOF && partNumber > 1 { + break + } + if rErr != nil && rErr != io.ErrUnexpectedEOF && rErr != io.EOF { + return 0, rErr + } + // Update progress reader appropriately to the latest offset + // as we read from the source. + rd := newHook(bytes.NewReader(buf[:length]), opts.Progress) + + // Proceed to upload the part. + var objPart ObjectPart + objPart, err = c.uploadPart(ctx, bucketName, objectName, uploadID, rd, partNumber, + "", "", int64(length), opts.ServerSideEncryption) + if err != nil { + return totalUploadedSize, err + } + + // Save successfully uploaded part metadata. + partsInfo[partNumber] = objPart + + // Save successfully uploaded size. + totalUploadedSize += int64(length) + + // Increment part number. + partNumber++ + + // For unknown size, Read EOF we break away. + // We do not have to upload till totalPartsCount. + if rErr == io.EOF { + break + } + } + + // Loop over total uploaded parts to save them in + // Parts array before completing the multipart request. + for i := 1; i < partNumber; i++ { + part, ok := partsInfo[i] + if !ok { + return 0, ErrInvalidArgument(fmt.Sprintf("Missing part number %d", i)) + } + complMultipartUpload.Parts = append(complMultipartUpload.Parts, CompletePart{ + ETag: part.ETag, + PartNumber: part.PartNumber, + }) + } + + // Sort all completed parts. + sort.Sort(completedParts(complMultipartUpload.Parts)) + if _, err = c.completeMultipartUpload(ctx, bucketName, objectName, uploadID, complMultipartUpload); err != nil { + return totalUploadedSize, err + } + + // Return final size. + return totalUploadedSize, nil +} diff --git a/vendor/github.com/minio/minio-go/api-remove.go b/vendor/github.com/minio/minio-go/api-remove.go new file mode 100644 index 0000000000000..f33df4dfc5e5d --- /dev/null +++ b/vendor/github.com/minio/minio-go/api-remove.go @@ -0,0 +1,303 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2015-2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package minio + +import ( + "bytes" + "context" + "encoding/xml" + "io" + "net/http" + "net/url" + + "github.com/minio/minio-go/pkg/s3utils" +) + +// RemoveBucket deletes the bucket name. +// +// All objects (including all object versions and delete markers). +// in the bucket must be deleted before successfully attempting this request. +func (c Client) RemoveBucket(bucketName string) error { + // Input validation. + if err := s3utils.CheckValidBucketName(bucketName); err != nil { + return err + } + // Execute DELETE on bucket. + resp, err := c.executeMethod(context.Background(), "DELETE", requestMetadata{ + bucketName: bucketName, + contentSHA256Hex: emptySHA256Hex, + }) + defer closeResponse(resp) + if err != nil { + return err + } + if resp != nil { + if resp.StatusCode != http.StatusNoContent { + return httpRespToErrorResponse(resp, bucketName, "") + } + } + + // Remove the location from cache on a successful delete. + c.bucketLocCache.Delete(bucketName) + + return nil +} + +// RemoveObject remove an object from a bucket. +func (c Client) RemoveObject(bucketName, objectName string) error { + // Input validation. + if err := s3utils.CheckValidBucketName(bucketName); err != nil { + return err + } + if err := s3utils.CheckValidObjectName(objectName); err != nil { + return err + } + // Execute DELETE on objectName. + resp, err := c.executeMethod(context.Background(), "DELETE", requestMetadata{ + bucketName: bucketName, + objectName: objectName, + contentSHA256Hex: emptySHA256Hex, + }) + defer closeResponse(resp) + if err != nil { + return err + } + if resp != nil { + // if some unexpected error happened and max retry is reached, we want to let client know + if resp.StatusCode != http.StatusNoContent { + return httpRespToErrorResponse(resp, bucketName, objectName) + } + } + + // DeleteObject always responds with http '204' even for + // objects which do not exist. So no need to handle them + // specifically. + return nil +} + +// RemoveObjectError - container of Multi Delete S3 API error +type RemoveObjectError struct { + ObjectName string + Err error +} + +// generateRemoveMultiObjects - generate the XML request for remove multi objects request +func generateRemoveMultiObjectsRequest(objects []string) []byte { + rmObjects := []deleteObject{} + for _, obj := range objects { + rmObjects = append(rmObjects, deleteObject{Key: obj}) + } + xmlBytes, _ := xml.Marshal(deleteMultiObjects{Objects: rmObjects, Quiet: true}) + return xmlBytes +} + +// processRemoveMultiObjectsResponse - parse the remove multi objects web service +// and return the success/failure result status for each object +func processRemoveMultiObjectsResponse(body io.Reader, objects []string, errorCh chan<- RemoveObjectError) { + // Parse multi delete XML response + rmResult := &deleteMultiObjectsResult{} + err := xmlDecoder(body, rmResult) + if err != nil { + errorCh <- RemoveObjectError{ObjectName: "", Err: err} + return + } + + // Fill deletion that returned an error. + for _, obj := range rmResult.UnDeletedObjects { + errorCh <- RemoveObjectError{ + ObjectName: obj.Key, + Err: ErrorResponse{ + Code: obj.Code, + Message: obj.Message, + }, + } + } +} + +// RemoveObjectsWithContext - Identical to RemoveObjects call, but accepts context to facilitate request cancellation. +func (c Client) RemoveObjectsWithContext(ctx context.Context, bucketName string, objectsCh <-chan string) <-chan RemoveObjectError { + errorCh := make(chan RemoveObjectError, 1) + + // Validate if bucket name is valid. + if err := s3utils.CheckValidBucketName(bucketName); err != nil { + defer close(errorCh) + errorCh <- RemoveObjectError{ + Err: err, + } + return errorCh + } + // Validate objects channel to be properly allocated. + if objectsCh == nil { + defer close(errorCh) + errorCh <- RemoveObjectError{ + Err: ErrInvalidArgument("Objects channel cannot be nil"), + } + return errorCh + } + + // Generate and call MultiDelete S3 requests based on entries received from objectsCh + go func(errorCh chan<- RemoveObjectError) { + maxEntries := 1000 + finish := false + urlValues := make(url.Values) + urlValues.Set("delete", "") + + // Close error channel when Multi delete finishes. + defer close(errorCh) + + // Loop over entries by 1000 and call MultiDelete requests + for { + if finish { + break + } + count := 0 + var batch []string + + // Try to gather 1000 entries + for object := range objectsCh { + batch = append(batch, object) + if count++; count >= maxEntries { + break + } + } + if count == 0 { + // Multi Objects Delete API doesn't accept empty object list, quit immediately + break + } + if count < maxEntries { + // We didn't have 1000 entries, so this is the last batch + finish = true + } + + // Generate remove multi objects XML request + removeBytes := generateRemoveMultiObjectsRequest(batch) + // Execute GET on bucket to list objects. + resp, err := c.executeMethod(ctx, "POST", requestMetadata{ + bucketName: bucketName, + queryValues: urlValues, + contentBody: bytes.NewReader(removeBytes), + contentLength: int64(len(removeBytes)), + contentMD5Base64: sumMD5Base64(removeBytes), + contentSHA256Hex: sum256Hex(removeBytes), + }) + if resp != nil { + if resp.StatusCode != http.StatusOK { + e := httpRespToErrorResponse(resp, bucketName, "") + errorCh <- RemoveObjectError{ObjectName: "", Err: e} + } + } + if err != nil { + for _, b := range batch { + errorCh <- RemoveObjectError{ObjectName: b, Err: err} + } + continue + } + + // Process multiobjects remove xml response + processRemoveMultiObjectsResponse(resp.Body, batch, errorCh) + + closeResponse(resp) + } + }(errorCh) + return errorCh +} + +// RemoveObjects removes multiple objects from a bucket. +// The list of objects to remove are received from objectsCh. +// Remove failures are sent back via error channel. +func (c Client) RemoveObjects(bucketName string, objectsCh <-chan string) <-chan RemoveObjectError { + return c.RemoveObjectsWithContext(context.Background(), bucketName, objectsCh) +} + +// RemoveIncompleteUpload aborts an partially uploaded object. +func (c Client) RemoveIncompleteUpload(bucketName, objectName string) error { + // Input validation. + if err := s3utils.CheckValidBucketName(bucketName); err != nil { + return err + } + if err := s3utils.CheckValidObjectName(objectName); err != nil { + return err + } + // Find multipart upload ids of the object to be aborted. + uploadIDs, err := c.findUploadIDs(bucketName, objectName) + if err != nil { + return err + } + + for _, uploadID := range uploadIDs { + // abort incomplete multipart upload, based on the upload id passed. + err := c.abortMultipartUpload(context.Background(), bucketName, objectName, uploadID) + if err != nil { + return err + } + } + + return nil +} + +// abortMultipartUpload aborts a multipart upload for the given +// uploadID, all previously uploaded parts are deleted. +func (c Client) abortMultipartUpload(ctx context.Context, bucketName, objectName, uploadID string) error { + // Input validation. + if err := s3utils.CheckValidBucketName(bucketName); err != nil { + return err + } + if err := s3utils.CheckValidObjectName(objectName); err != nil { + return err + } + + // Initialize url queries. + urlValues := make(url.Values) + urlValues.Set("uploadId", uploadID) + + // Execute DELETE on multipart upload. + resp, err := c.executeMethod(ctx, "DELETE", requestMetadata{ + bucketName: bucketName, + objectName: objectName, + queryValues: urlValues, + contentSHA256Hex: emptySHA256Hex, + }) + defer closeResponse(resp) + if err != nil { + return err + } + if resp != nil { + if resp.StatusCode != http.StatusNoContent { + // Abort has no response body, handle it for any errors. + var errorResponse ErrorResponse + switch resp.StatusCode { + case http.StatusNotFound: + // This is needed specifically for abort and it cannot + // be converged into default case. + errorResponse = ErrorResponse{ + Code: "NoSuchUpload", + Message: "The specified multipart upload does not exist.", + BucketName: bucketName, + Key: objectName, + RequestID: resp.Header.Get("x-amz-request-id"), + HostID: resp.Header.Get("x-amz-id-2"), + Region: resp.Header.Get("x-amz-bucket-region"), + } + default: + return httpRespToErrorResponse(resp, bucketName, objectName) + } + return errorResponse + } + } + return nil +} diff --git a/vendor/github.com/minio/minio-go/api-s3-datatypes.go b/vendor/github.com/minio/minio-go/api-s3-datatypes.go new file mode 100644 index 0000000000000..8d8880c0514b7 --- /dev/null +++ b/vendor/github.com/minio/minio-go/api-s3-datatypes.go @@ -0,0 +1,245 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2015-2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package minio + +import ( + "encoding/xml" + "time" +) + +// listAllMyBucketsResult container for listBuckets response. +type listAllMyBucketsResult struct { + // Container for one or more buckets. + Buckets struct { + Bucket []BucketInfo + } + Owner owner +} + +// owner container for bucket owner information. +type owner struct { + DisplayName string + ID string +} + +// CommonPrefix container for prefix response. +type CommonPrefix struct { + Prefix string +} + +// ListBucketV2Result container for listObjects response version 2. +type ListBucketV2Result struct { + // A response can contain CommonPrefixes only if you have + // specified a delimiter. + CommonPrefixes []CommonPrefix + // Metadata about each object returned. + Contents []ObjectInfo + Delimiter string + + // Encoding type used to encode object keys in the response. + EncodingType string + + // A flag that indicates whether or not ListObjects returned all of the results + // that satisfied the search criteria. + IsTruncated bool + MaxKeys int64 + Name string + + // Hold the token that will be sent in the next request to fetch the next group of keys + NextContinuationToken string + + ContinuationToken string + Prefix string + + // FetchOwner and StartAfter are currently not used + FetchOwner string + StartAfter string +} + +// ListBucketResult container for listObjects response. +type ListBucketResult struct { + // A response can contain CommonPrefixes only if you have + // specified a delimiter. + CommonPrefixes []CommonPrefix + // Metadata about each object returned. + Contents []ObjectInfo + Delimiter string + + // Encoding type used to encode object keys in the response. + EncodingType string + + // A flag that indicates whether or not ListObjects returned all of the results + // that satisfied the search criteria. + IsTruncated bool + Marker string + MaxKeys int64 + Name string + + // When response is truncated (the IsTruncated element value in + // the response is true), you can use the key name in this field + // as marker in the subsequent request to get next set of objects. + // Object storage lists objects in alphabetical order Note: This + // element is returned only if you have delimiter request + // parameter specified. If response does not include the NextMaker + // and it is truncated, you can use the value of the last Key in + // the response as the marker in the subsequent request to get the + // next set of object keys. + NextMarker string + Prefix string +} + +// ListMultipartUploadsResult container for ListMultipartUploads response +type ListMultipartUploadsResult struct { + Bucket string + KeyMarker string + UploadIDMarker string `xml:"UploadIdMarker"` + NextKeyMarker string + NextUploadIDMarker string `xml:"NextUploadIdMarker"` + EncodingType string + MaxUploads int64 + IsTruncated bool + Uploads []ObjectMultipartInfo `xml:"Upload"` + Prefix string + Delimiter string + // A response can contain CommonPrefixes only if you specify a delimiter. + CommonPrefixes []CommonPrefix +} + +// initiator container for who initiated multipart upload. +type initiator struct { + ID string + DisplayName string +} + +// copyObjectResult container for copy object response. +type copyObjectResult struct { + ETag string + LastModified time.Time // time string format "2006-01-02T15:04:05.000Z" +} + +// ObjectPart container for particular part of an object. +type ObjectPart struct { + // Part number identifies the part. + PartNumber int + + // Date and time the part was uploaded. + LastModified time.Time + + // Entity tag returned when the part was uploaded, usually md5sum + // of the part. + ETag string + + // Size of the uploaded part data. + Size int64 +} + +// ListObjectPartsResult container for ListObjectParts response. +type ListObjectPartsResult struct { + Bucket string + Key string + UploadID string `xml:"UploadId"` + + Initiator initiator + Owner owner + + StorageClass string + PartNumberMarker int + NextPartNumberMarker int + MaxParts int + + // Indicates whether the returned list of parts is truncated. + IsTruncated bool + ObjectParts []ObjectPart `xml:"Part"` + + EncodingType string +} + +// initiateMultipartUploadResult container for InitiateMultiPartUpload +// response. +type initiateMultipartUploadResult struct { + Bucket string + Key string + UploadID string `xml:"UploadId"` +} + +// completeMultipartUploadResult container for completed multipart +// upload response. +type completeMultipartUploadResult struct { + Location string + Bucket string + Key string + ETag string +} + +// CompletePart sub container lists individual part numbers and their +// md5sum, part of completeMultipartUpload. +type CompletePart struct { + XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ Part" json:"-"` + + // Part number identifies the part. + PartNumber int + ETag string +} + +// completeMultipartUpload container for completing multipart upload. +type completeMultipartUpload struct { + XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ CompleteMultipartUpload" json:"-"` + Parts []CompletePart `xml:"Part"` +} + +// createBucketConfiguration container for bucket configuration. +type createBucketConfiguration struct { + XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ CreateBucketConfiguration" json:"-"` + Location string `xml:"LocationConstraint"` +} + +// deleteObject container for Delete element in MultiObjects Delete XML request +type deleteObject struct { + Key string + VersionID string `xml:"VersionId,omitempty"` +} + +// deletedObject container for Deleted element in MultiObjects Delete XML response +type deletedObject struct { + Key string + VersionID string `xml:"VersionId,omitempty"` + // These fields are ignored. + DeleteMarker bool + DeleteMarkerVersionID string +} + +// nonDeletedObject container for Error element (failed deletion) in MultiObjects Delete XML response +type nonDeletedObject struct { + Key string + Code string + Message string +} + +// deletedMultiObjects container for MultiObjects Delete XML request +type deleteMultiObjects struct { + XMLName xml.Name `xml:"Delete"` + Quiet bool + Objects []deleteObject `xml:"Object"` +} + +// deletedMultiObjectsResult container for MultiObjects Delete XML response +type deleteMultiObjectsResult struct { + XMLName xml.Name `xml:"DeleteResult"` + DeletedObjects []deletedObject `xml:"Deleted"` + UnDeletedObjects []nonDeletedObject `xml:"Error"` +} diff --git a/vendor/github.com/minio/minio-go/api-select.go b/vendor/github.com/minio/minio-go/api-select.go new file mode 100644 index 0000000000000..10e1d47d6375c --- /dev/null +++ b/vendor/github.com/minio/minio-go/api-select.go @@ -0,0 +1,532 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * (C) 2018 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package minio + +import ( + "bytes" + "context" + "encoding/binary" + "encoding/xml" + "errors" + "fmt" + "hash" + "hash/crc32" + "io" + "net/http" + "net/url" + "strings" + + "github.com/minio/minio-go/pkg/encrypt" + "github.com/minio/minio-go/pkg/s3utils" +) + +// CSVFileHeaderInfo - is the parameter for whether to utilize headers. +type CSVFileHeaderInfo string + +// Constants for file header info. +const ( + CSVFileHeaderInfoNone CSVFileHeaderInfo = "NONE" + CSVFileHeaderInfoIgnore = "IGNORE" + CSVFileHeaderInfoUse = "USE" +) + +// SelectCompressionType - is the parameter for what type of compression is +// present +type SelectCompressionType string + +// Constants for compression types under select API. +const ( + SelectCompressionNONE SelectCompressionType = "NONE" + SelectCompressionGZIP = "GZIP" + SelectCompressionBZIP = "BZIP2" +) + +// CSVQuoteFields - is the parameter for how CSV fields are quoted. +type CSVQuoteFields string + +// Constants for csv quote styles. +const ( + CSVQuoteFieldsAlways CSVQuoteFields = "Always" + CSVQuoteFieldsAsNeeded = "AsNeeded" +) + +// QueryExpressionType - is of what syntax the expression is, this should only +// be SQL +type QueryExpressionType string + +// Constants for expression type. +const ( + QueryExpressionTypeSQL QueryExpressionType = "SQL" +) + +// JSONType determines json input serialization type. +type JSONType string + +// Constants for JSONTypes. +const ( + JSONDocumentType JSONType = "DOCUMENT" + JSONLinesType = "LINES" +) + +// ParquetInputOptions parquet input specific options +type ParquetInputOptions struct{} + +// CSVInputOptions csv input specific options +type CSVInputOptions struct { + FileHeaderInfo CSVFileHeaderInfo + RecordDelimiter string + FieldDelimiter string + QuoteCharacter string + QuoteEscapeCharacter string + Comments string +} + +// CSVOutputOptions csv output specific options +type CSVOutputOptions struct { + QuoteFields CSVQuoteFields + RecordDelimiter string + FieldDelimiter string + QuoteCharacter string + QuoteEscapeCharacter string +} + +// JSONInputOptions json input specific options +type JSONInputOptions struct { + Type JSONType +} + +// JSONOutputOptions - json output specific options +type JSONOutputOptions struct { + RecordDelimiter string +} + +// SelectObjectInputSerialization - input serialization parameters +type SelectObjectInputSerialization struct { + CompressionType SelectCompressionType + Parquet *ParquetInputOptions `xml:"Parquet,omitempty"` + CSV *CSVInputOptions `xml:"CSV,omitempty"` + JSON *JSONInputOptions `xml:"JSON,omitempty"` +} + +// SelectObjectOutputSerialization - output serialization parameters. +type SelectObjectOutputSerialization struct { + CSV *CSVOutputOptions `xml:"CSV,omitempty"` + JSON *JSONOutputOptions `xml:"JSON,omitempty"` +} + +// SelectObjectOptions - represents the input select body +type SelectObjectOptions struct { + XMLName xml.Name `xml:"SelectObjectContentRequest" json:"-"` + ServerSideEncryption encrypt.ServerSide `xml:"-"` + Expression string + ExpressionType QueryExpressionType + InputSerialization SelectObjectInputSerialization + OutputSerialization SelectObjectOutputSerialization + RequestProgress struct { + Enabled bool + } +} + +// Header returns the http.Header representation of the SelectObject options. +func (o SelectObjectOptions) Header() http.Header { + headers := make(http.Header) + if o.ServerSideEncryption != nil && o.ServerSideEncryption.Type() == encrypt.SSEC { + o.ServerSideEncryption.Marshal(headers) + } + return headers +} + +// SelectObjectType - is the parameter which defines what type of object the +// operation is being performed on. +type SelectObjectType string + +// Constants for input data types. +const ( + SelectObjectTypeCSV SelectObjectType = "CSV" + SelectObjectTypeJSON = "JSON" + SelectObjectTypeParquet = "Parquet" +) + +// preludeInfo is used for keeping track of necessary information from the +// prelude. +type preludeInfo struct { + totalLen uint32 + headerLen uint32 +} + +// SelectResults is used for the streaming responses from the server. +type SelectResults struct { + pipeReader *io.PipeReader + resp *http.Response + stats *StatsMessage + progress *ProgressMessage +} + +// ProgressMessage is a struct for progress xml message. +type ProgressMessage struct { + XMLName xml.Name `xml:"Progress" json:"-"` + StatsMessage +} + +// StatsMessage is a struct for stat xml message. +type StatsMessage struct { + XMLName xml.Name `xml:"Stats" json:"-"` + BytesScanned int64 + BytesProcessed int64 + BytesReturned int64 +} + +// messageType represents the type of message. +type messageType string + +const ( + errorMsg messageType = "error" + commonMsg = "event" +) + +// eventType represents the type of event. +type eventType string + +// list of event-types returned by Select API. +const ( + endEvent eventType = "End" + recordsEvent = "Records" + progressEvent = "Progress" + statsEvent = "Stats" +) + +// contentType represents content type of event. +type contentType string + +const ( + xmlContent contentType = "text/xml" +) + +// SelectObjectContent is a implementation of http://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectSELECTContent.html AWS S3 API. +func (c Client) SelectObjectContent(ctx context.Context, bucketName, objectName string, opts SelectObjectOptions) (*SelectResults, error) { + // Input validation. + if err := s3utils.CheckValidBucketName(bucketName); err != nil { + return nil, err + } + if err := s3utils.CheckValidObjectName(objectName); err != nil { + return nil, err + } + + selectReqBytes, err := xml.Marshal(opts) + if err != nil { + return nil, err + } + + urlValues := make(url.Values) + urlValues.Set("select", "") + urlValues.Set("select-type", "2") + + // Execute POST on bucket/object. + resp, err := c.executeMethod(ctx, "POST", requestMetadata{ + bucketName: bucketName, + objectName: objectName, + queryValues: urlValues, + customHeader: opts.Header(), + contentMD5Base64: sumMD5Base64(selectReqBytes), + contentSHA256Hex: sum256Hex(selectReqBytes), + contentBody: bytes.NewReader(selectReqBytes), + contentLength: int64(len(selectReqBytes)), + }) + if err != nil { + return nil, err + } + + if resp.StatusCode != http.StatusOK { + return nil, httpRespToErrorResponse(resp, bucketName, "") + } + + pipeReader, pipeWriter := io.Pipe() + streamer := &SelectResults{ + resp: resp, + stats: &StatsMessage{}, + progress: &ProgressMessage{}, + pipeReader: pipeReader, + } + streamer.start(pipeWriter) + return streamer, nil +} + +// Close - closes the underlying response body and the stream reader. +func (s *SelectResults) Close() error { + defer closeResponse(s.resp) + return s.pipeReader.Close() +} + +// Read - is a reader compatible implementation for SelectObjectContent records. +func (s *SelectResults) Read(b []byte) (n int, err error) { + return s.pipeReader.Read(b) +} + +// Stats - information about a request's stats when processing is complete. +func (s *SelectResults) Stats() *StatsMessage { + return s.stats +} + +// Progress - information about the progress of a request. +func (s *SelectResults) Progress() *ProgressMessage { + return s.progress +} + +// start is the main function that decodes the large byte array into +// several events that are sent through the eventstream. +func (s *SelectResults) start(pipeWriter *io.PipeWriter) { + go func() { + for { + var prelude preludeInfo + var headers = make(http.Header) + var err error + + // Create CRC code + crc := crc32.New(crc32.IEEETable) + crcReader := io.TeeReader(s.resp.Body, crc) + + // Extract the prelude(12 bytes) into a struct to extract relevant information. + prelude, err = processPrelude(crcReader, crc) + if err != nil { + pipeWriter.CloseWithError(err) + closeResponse(s.resp) + return + } + + // Extract the headers(variable bytes) into a struct to extract relevant information + if prelude.headerLen > 0 { + if err = extractHeader(io.LimitReader(crcReader, int64(prelude.headerLen)), headers); err != nil { + pipeWriter.CloseWithError(err) + closeResponse(s.resp) + return + } + } + + // Get the actual payload length so that the appropriate amount of + // bytes can be read or parsed. + payloadLen := prelude.PayloadLen() + + m := messageType(headers.Get("message-type")) + + switch m { + case errorMsg: + pipeWriter.CloseWithError(errors.New("Error Type of " + headers.Get("error-type") + " " + headers.Get("error-message"))) + closeResponse(s.resp) + return + case commonMsg: + // Get content-type of the payload. + c := contentType(headers.Get("content-type")) + + // Get event type of the payload. + e := eventType(headers.Get("event-type")) + + // Handle all supported events. + switch e { + case endEvent: + pipeWriter.Close() + closeResponse(s.resp) + return + case recordsEvent: + if _, err = io.Copy(pipeWriter, io.LimitReader(crcReader, payloadLen)); err != nil { + pipeWriter.CloseWithError(err) + closeResponse(s.resp) + return + } + case progressEvent: + switch c { + case xmlContent: + if err = xmlDecoder(io.LimitReader(crcReader, payloadLen), s.progress); err != nil { + pipeWriter.CloseWithError(err) + closeResponse(s.resp) + return + } + default: + pipeWriter.CloseWithError(fmt.Errorf("Unexpected content-type %s sent for event-type %s", c, progressEvent)) + closeResponse(s.resp) + return + } + case statsEvent: + switch c { + case xmlContent: + if err = xmlDecoder(io.LimitReader(crcReader, payloadLen), s.stats); err != nil { + pipeWriter.CloseWithError(err) + closeResponse(s.resp) + return + } + default: + pipeWriter.CloseWithError(fmt.Errorf("Unexpected content-type %s sent for event-type %s", c, statsEvent)) + closeResponse(s.resp) + return + } + } + } + + // Ensures that the full message's CRC is correct and + // that the message is not corrupted + if err := checkCRC(s.resp.Body, crc.Sum32()); err != nil { + pipeWriter.CloseWithError(err) + closeResponse(s.resp) + return + } + + } + }() +} + +// PayloadLen is a function that calculates the length of the payload. +func (p preludeInfo) PayloadLen() int64 { + return int64(p.totalLen - p.headerLen - 16) +} + +// processPrelude is the function that reads the 12 bytes of the prelude and +// ensures the CRC is correct while also extracting relevant information into +// the struct, +func processPrelude(prelude io.Reader, crc hash.Hash32) (preludeInfo, error) { + var err error + var pInfo = preludeInfo{} + + // reads total length of the message (first 4 bytes) + pInfo.totalLen, err = extractUint32(prelude) + if err != nil { + return pInfo, err + } + + // reads total header length of the message (2nd 4 bytes) + pInfo.headerLen, err = extractUint32(prelude) + if err != nil { + return pInfo, err + } + + // checks that the CRC is correct (3rd 4 bytes) + preCRC := crc.Sum32() + if err := checkCRC(prelude, preCRC); err != nil { + return pInfo, err + } + + return pInfo, nil +} + +// extracts the relevant information from the Headers. +func extractHeader(body io.Reader, myHeaders http.Header) error { + for { + // extracts the first part of the header, + headerTypeName, err := extractHeaderType(body) + if err != nil { + // Since end of file, we have read all of our headers + if err == io.EOF { + break + } + return err + } + + // reads the 7 present in the header and ignores it. + extractUint8(body) + + headerValueName, err := extractHeaderValue(body) + if err != nil { + return err + } + + myHeaders.Set(headerTypeName, headerValueName) + + } + return nil +} + +// extractHeaderType extracts the first half of the header message, the header type. +func extractHeaderType(body io.Reader) (string, error) { + // extracts 2 bit integer + headerNameLen, err := extractUint8(body) + if err != nil { + return "", err + } + // extracts the string with the appropriate number of bytes + headerName, err := extractString(body, int(headerNameLen)) + if err != nil { + return "", err + } + return strings.TrimPrefix(headerName, ":"), nil +} + +// extractsHeaderValue extracts the second half of the header message, the +// header value +func extractHeaderValue(body io.Reader) (string, error) { + bodyLen, err := extractUint16(body) + if err != nil { + return "", err + } + bodyName, err := extractString(body, int(bodyLen)) + if err != nil { + return "", err + } + return bodyName, nil +} + +// extracts a string from byte array of a particular number of bytes. +func extractString(source io.Reader, lenBytes int) (string, error) { + myVal := make([]byte, lenBytes) + _, err := source.Read(myVal) + if err != nil { + return "", err + } + return string(myVal), nil +} + +// extractUint32 extracts a 4 byte integer from the byte array. +func extractUint32(r io.Reader) (uint32, error) { + buf := make([]byte, 4) + _, err := io.ReadFull(r, buf) + if err != nil { + return 0, err + } + return binary.BigEndian.Uint32(buf), nil +} + +// extractUint16 extracts a 2 byte integer from the byte array. +func extractUint16(r io.Reader) (uint16, error) { + buf := make([]byte, 2) + _, err := io.ReadFull(r, buf) + if err != nil { + return 0, err + } + return binary.BigEndian.Uint16(buf), nil +} + +// extractUint8 extracts a 1 byte integer from the byte array. +func extractUint8(r io.Reader) (uint8, error) { + buf := make([]byte, 1) + _, err := io.ReadFull(r, buf) + if err != nil { + return 0, err + } + return buf[0], nil +} + +// checkCRC ensures that the CRC matches with the one from the reader. +func checkCRC(r io.Reader, expect uint32) error { + msgCRC, err := extractUint32(r) + if err != nil { + return err + } + + if msgCRC != expect { + return fmt.Errorf("Checksum Mismatch, MessageCRC of 0x%X does not equal expected CRC of 0x%X", msgCRC, expect) + + } + return nil +} diff --git a/vendor/github.com/minio/minio-go/api-stat.go b/vendor/github.com/minio/minio-go/api-stat.go new file mode 100644 index 0000000000000..91e9d3964a111 --- /dev/null +++ b/vendor/github.com/minio/minio-go/api-stat.go @@ -0,0 +1,185 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2015-2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package minio + +import ( + "context" + "net/http" + "strconv" + "strings" + "time" + + "github.com/minio/minio-go/pkg/s3utils" +) + +// BucketExists verify if bucket exists and you have permission to access it. +func (c Client) BucketExists(bucketName string) (bool, error) { + // Input validation. + if err := s3utils.CheckValidBucketName(bucketName); err != nil { + return false, err + } + + // Execute HEAD on bucketName. + resp, err := c.executeMethod(context.Background(), "HEAD", requestMetadata{ + bucketName: bucketName, + contentSHA256Hex: emptySHA256Hex, + }) + defer closeResponse(resp) + if err != nil { + if ToErrorResponse(err).Code == "NoSuchBucket" { + return false, nil + } + return false, err + } + if resp != nil { + resperr := httpRespToErrorResponse(resp, bucketName, "") + if ToErrorResponse(resperr).Code == "NoSuchBucket" { + return false, nil + } + if resp.StatusCode != http.StatusOK { + return false, httpRespToErrorResponse(resp, bucketName, "") + } + } + return true, nil +} + +// List of header keys to be filtered, usually +// from all S3 API http responses. +var defaultFilterKeys = []string{ + "Connection", + "Transfer-Encoding", + "Accept-Ranges", + "Date", + "Server", + "Vary", + "x-amz-bucket-region", + "x-amz-request-id", + "x-amz-id-2", + "Content-Security-Policy", + "X-Xss-Protection", + + // Add new headers to be ignored. +} + +// Extract only necessary metadata header key/values by +// filtering them out with a list of custom header keys. +func extractObjMetadata(header http.Header) http.Header { + filterKeys := append([]string{ + "ETag", + "Content-Length", + "Last-Modified", + "Content-Type", + }, defaultFilterKeys...) + return filterHeader(header, filterKeys) +} + +// StatObject verifies if object exists and you have permission to access. +func (c Client) StatObject(bucketName, objectName string, opts StatObjectOptions) (ObjectInfo, error) { + // Input validation. + if err := s3utils.CheckValidBucketName(bucketName); err != nil { + return ObjectInfo{}, err + } + if err := s3utils.CheckValidObjectName(objectName); err != nil { + return ObjectInfo{}, err + } + return c.statObject(context.Background(), bucketName, objectName, opts) +} + +// Lower level API for statObject supporting pre-conditions and range headers. +func (c Client) statObject(ctx context.Context, bucketName, objectName string, opts StatObjectOptions) (ObjectInfo, error) { + // Input validation. + if err := s3utils.CheckValidBucketName(bucketName); err != nil { + return ObjectInfo{}, err + } + if err := s3utils.CheckValidObjectName(objectName); err != nil { + return ObjectInfo{}, err + } + + // Execute HEAD on objectName. + resp, err := c.executeMethod(ctx, "HEAD", requestMetadata{ + bucketName: bucketName, + objectName: objectName, + contentSHA256Hex: emptySHA256Hex, + customHeader: opts.Header(), + }) + defer closeResponse(resp) + if err != nil { + return ObjectInfo{}, err + } + if resp != nil { + if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusPartialContent { + return ObjectInfo{}, httpRespToErrorResponse(resp, bucketName, objectName) + } + } + + // Trim off the odd double quotes from ETag in the beginning and end. + md5sum := strings.TrimPrefix(resp.Header.Get("ETag"), "\"") + md5sum = strings.TrimSuffix(md5sum, "\"") + + // Parse content length is exists + var size int64 = -1 + contentLengthStr := resp.Header.Get("Content-Length") + if contentLengthStr != "" { + size, err = strconv.ParseInt(contentLengthStr, 10, 64) + if err != nil { + // Content-Length is not valid + return ObjectInfo{}, ErrorResponse{ + Code: "InternalError", + Message: "Content-Length is invalid. " + reportIssue, + BucketName: bucketName, + Key: objectName, + RequestID: resp.Header.Get("x-amz-request-id"), + HostID: resp.Header.Get("x-amz-id-2"), + Region: resp.Header.Get("x-amz-bucket-region"), + } + } + } + + // Parse Last-Modified has http time format. + date, err := time.Parse(http.TimeFormat, resp.Header.Get("Last-Modified")) + if err != nil { + return ObjectInfo{}, ErrorResponse{ + Code: "InternalError", + Message: "Last-Modified time format is invalid. " + reportIssue, + BucketName: bucketName, + Key: objectName, + RequestID: resp.Header.Get("x-amz-request-id"), + HostID: resp.Header.Get("x-amz-id-2"), + Region: resp.Header.Get("x-amz-bucket-region"), + } + } + + // Fetch content type if any present. + contentType := strings.TrimSpace(resp.Header.Get("Content-Type")) + if contentType == "" { + contentType = "application/octet-stream" + } + + // Save object metadata info. + return ObjectInfo{ + ETag: md5sum, + Key: objectName, + Size: size, + LastModified: date, + ContentType: contentType, + // Extract only the relevant header keys describing the object. + // following function filters out a list of standard set of keys + // which are not part of object metadata. + Metadata: extractObjMetadata(resp.Header), + }, nil +} diff --git a/vendor/github.com/minio/minio-go/api.go b/vendor/github.com/minio/minio-go/api.go new file mode 100644 index 0000000000000..f1c54909fac70 --- /dev/null +++ b/vendor/github.com/minio/minio-go/api.go @@ -0,0 +1,898 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2015-2018 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package minio + +import ( + "bytes" + "context" + "crypto/md5" + "crypto/sha256" + "errors" + "fmt" + "hash" + "io" + "io/ioutil" + "math/rand" + "net" + "net/http" + "net/http/cookiejar" + "net/http/httputil" + "net/url" + "os" + "runtime" + "strings" + "sync" + "time" + + "golang.org/x/net/publicsuffix" + + "github.com/minio/minio-go/pkg/credentials" + "github.com/minio/minio-go/pkg/s3signer" + "github.com/minio/minio-go/pkg/s3utils" +) + +// Client implements Amazon S3 compatible methods. +type Client struct { + /// Standard options. + + // Parsed endpoint url provided by the user. + endpointURL *url.URL + + // Holds various credential providers. + credsProvider *credentials.Credentials + + // Custom signerType value overrides all credentials. + overrideSignerType credentials.SignatureType + + // User supplied. + appInfo struct { + appName string + appVersion string + } + + // Indicate whether we are using https or not + secure bool + + // Needs allocation. + httpClient *http.Client + bucketLocCache *bucketLocationCache + + // Advanced functionality. + isTraceEnabled bool + traceOutput io.Writer + + // S3 specific accelerated endpoint. + s3AccelerateEndpoint string + + // Region endpoint + region string + + // Random seed. + random *rand.Rand + + // lookup indicates type of url lookup supported by server. If not specified, + // default to Auto. + lookup BucketLookupType +} + +// Options for New method +type Options struct { + Creds *credentials.Credentials + Secure bool + Region string + BucketLookup BucketLookupType + // Add future fields here +} + +// Global constants. +const ( + libraryName = "minio-go" + libraryVersion = "v6.0.14" +) + +// User Agent should always following the below style. +// Please open an issue to discuss any new changes here. +// +// Minio (OS; ARCH) LIB/VER APP/VER +const ( + libraryUserAgentPrefix = "Minio (" + runtime.GOOS + "; " + runtime.GOARCH + ") " + libraryUserAgent = libraryUserAgentPrefix + libraryName + "/" + libraryVersion +) + +// BucketLookupType is type of url lookup supported by server. +type BucketLookupType int + +// Different types of url lookup supported by the server.Initialized to BucketLookupAuto +const ( + BucketLookupAuto BucketLookupType = iota + BucketLookupDNS + BucketLookupPath +) + +// NewV2 - instantiate minio client with Amazon S3 signature version +// '2' compatibility. +func NewV2(endpoint string, accessKeyID, secretAccessKey string, secure bool) (*Client, error) { + creds := credentials.NewStaticV2(accessKeyID, secretAccessKey, "") + clnt, err := privateNew(endpoint, creds, secure, "", BucketLookupAuto) + if err != nil { + return nil, err + } + clnt.overrideSignerType = credentials.SignatureV2 + return clnt, nil +} + +// NewV4 - instantiate minio client with Amazon S3 signature version +// '4' compatibility. +func NewV4(endpoint string, accessKeyID, secretAccessKey string, secure bool) (*Client, error) { + creds := credentials.NewStaticV4(accessKeyID, secretAccessKey, "") + clnt, err := privateNew(endpoint, creds, secure, "", BucketLookupAuto) + if err != nil { + return nil, err + } + clnt.overrideSignerType = credentials.SignatureV4 + return clnt, nil +} + +// New - instantiate minio client, adds automatic verification of signature. +func New(endpoint, accessKeyID, secretAccessKey string, secure bool) (*Client, error) { + creds := credentials.NewStaticV4(accessKeyID, secretAccessKey, "") + clnt, err := privateNew(endpoint, creds, secure, "", BucketLookupAuto) + if err != nil { + return nil, err + } + // Google cloud storage should be set to signature V2, force it if not. + if s3utils.IsGoogleEndpoint(*clnt.endpointURL) { + clnt.overrideSignerType = credentials.SignatureV2 + } + // If Amazon S3 set to signature v4. + if s3utils.IsAmazonEndpoint(*clnt.endpointURL) { + clnt.overrideSignerType = credentials.SignatureV4 + } + return clnt, nil +} + +// NewWithCredentials - instantiate minio client with credentials provider +// for retrieving credentials from various credentials provider such as +// IAM, File, Env etc. +func NewWithCredentials(endpoint string, creds *credentials.Credentials, secure bool, region string) (*Client, error) { + return privateNew(endpoint, creds, secure, region, BucketLookupAuto) +} + +// NewWithRegion - instantiate minio client, with region configured. Unlike New(), +// NewWithRegion avoids bucket-location lookup operations and it is slightly faster. +// Use this function when if your application deals with single region. +func NewWithRegion(endpoint, accessKeyID, secretAccessKey string, secure bool, region string) (*Client, error) { + creds := credentials.NewStaticV4(accessKeyID, secretAccessKey, "") + return privateNew(endpoint, creds, secure, region, BucketLookupAuto) +} + +// NewWithOptions - instantiate minio client with options +func NewWithOptions(endpoint string, opts *Options) (*Client, error) { + return privateNew(endpoint, opts.Creds, opts.Secure, opts.Region, opts.BucketLookup) +} + +// lockedRandSource provides protected rand source, implements rand.Source interface. +type lockedRandSource struct { + lk sync.Mutex + src rand.Source +} + +// Int63 returns a non-negative pseudo-random 63-bit integer as an int64. +func (r *lockedRandSource) Int63() (n int64) { + r.lk.Lock() + n = r.src.Int63() + r.lk.Unlock() + return +} + +// Seed uses the provided seed value to initialize the generator to a +// deterministic state. +func (r *lockedRandSource) Seed(seed int64) { + r.lk.Lock() + r.src.Seed(seed) + r.lk.Unlock() +} + +// Redirect requests by re signing the request. +func (c *Client) redirectHeaders(req *http.Request, via []*http.Request) error { + if len(via) >= 5 { + return errors.New("stopped after 5 redirects") + } + if len(via) == 0 { + return nil + } + lastRequest := via[len(via)-1] + var reAuth bool + for attr, val := range lastRequest.Header { + // if hosts do not match do not copy Authorization header + if attr == "Authorization" && req.Host != lastRequest.Host { + reAuth = true + continue + } + if _, ok := req.Header[attr]; !ok { + req.Header[attr] = val + } + } + + *c.endpointURL = *req.URL + + value, err := c.credsProvider.Get() + if err != nil { + return err + } + var ( + signerType = value.SignerType + accessKeyID = value.AccessKeyID + secretAccessKey = value.SecretAccessKey + sessionToken = value.SessionToken + region = c.region + ) + + // Custom signer set then override the behavior. + if c.overrideSignerType != credentials.SignatureDefault { + signerType = c.overrideSignerType + } + + // If signerType returned by credentials helper is anonymous, + // then do not sign regardless of signerType override. + if value.SignerType == credentials.SignatureAnonymous { + signerType = credentials.SignatureAnonymous + } + + if reAuth { + // Check if there is no region override, if not get it from the URL if possible. + if region == "" { + region = s3utils.GetRegionFromURL(*c.endpointURL) + } + switch { + case signerType.IsV2(): + return errors.New("signature V2 cannot support redirection") + case signerType.IsV4(): + req = s3signer.SignV4(*req, accessKeyID, secretAccessKey, sessionToken, getDefaultLocation(*c.endpointURL, region)) + } + } + return nil +} + +func privateNew(endpoint string, creds *credentials.Credentials, secure bool, region string, lookup BucketLookupType) (*Client, error) { + // construct endpoint. + endpointURL, err := getEndpointURL(endpoint, secure) + if err != nil { + return nil, err + } + + // Initialize cookies to preserve server sent cookies if any and replay + // them upon each request. + jar, err := cookiejar.New(&cookiejar.Options{PublicSuffixList: publicsuffix.List}) + if err != nil { + return nil, err + } + + // instantiate new Client. + clnt := new(Client) + + // Save the credentials. + clnt.credsProvider = creds + + // Remember whether we are using https or not + clnt.secure = secure + + // Save endpoint URL, user agent for future uses. + clnt.endpointURL = endpointURL + + // Instantiate http client and bucket location cache. + clnt.httpClient = &http.Client{ + Jar: jar, + Transport: DefaultTransport, + CheckRedirect: clnt.redirectHeaders, + } + + // Sets custom region, if region is empty bucket location cache is used automatically. + if region == "" { + region = s3utils.GetRegionFromURL(*clnt.endpointURL) + } + clnt.region = region + + // Instantiate bucket location cache. + clnt.bucketLocCache = newBucketLocationCache() + + // Introduce a new locked random seed. + clnt.random = rand.New(&lockedRandSource{src: rand.NewSource(time.Now().UTC().UnixNano())}) + + // Sets bucket lookup style, whether server accepts DNS or Path lookup. Default is Auto - determined + // by the SDK. When Auto is specified, DNS lookup is used for Amazon/Google cloud endpoints and Path for all other endpoints. + clnt.lookup = lookup + // Return. + return clnt, nil +} + +// SetAppInfo - add application details to user agent. +func (c *Client) SetAppInfo(appName string, appVersion string) { + // if app name and version not set, we do not set a new user agent. + if appName != "" && appVersion != "" { + c.appInfo = struct { + appName string + appVersion string + }{} + c.appInfo.appName = appName + c.appInfo.appVersion = appVersion + } +} + +// SetCustomTransport - set new custom transport. +func (c *Client) SetCustomTransport(customHTTPTransport http.RoundTripper) { + // Set this to override default transport + // ``http.DefaultTransport``. + // + // This transport is usually needed for debugging OR to add your + // own custom TLS certificates on the client transport, for custom + // CA's and certs which are not part of standard certificate + // authority follow this example :- + // + // tr := &http.Transport{ + // TLSClientConfig: &tls.Config{RootCAs: pool}, + // DisableCompression: true, + // } + // api.SetCustomTransport(tr) + // + if c.httpClient != nil { + c.httpClient.Transport = customHTTPTransport + } +} + +// TraceOn - enable HTTP tracing. +func (c *Client) TraceOn(outputStream io.Writer) { + // if outputStream is nil then default to os.Stdout. + if outputStream == nil { + outputStream = os.Stdout + } + // Sets a new output stream. + c.traceOutput = outputStream + + // Enable tracing. + c.isTraceEnabled = true +} + +// TraceOff - disable HTTP tracing. +func (c *Client) TraceOff() { + // Disable tracing. + c.isTraceEnabled = false +} + +// SetS3TransferAccelerate - turns s3 accelerated endpoint on or off for all your +// requests. This feature is only specific to S3 for all other endpoints this +// function does nothing. To read further details on s3 transfer acceleration +// please vist - +// http://docs.aws.amazon.com/AmazonS3/latest/dev/transfer-acceleration.html +func (c *Client) SetS3TransferAccelerate(accelerateEndpoint string) { + if s3utils.IsAmazonEndpoint(*c.endpointURL) { + c.s3AccelerateEndpoint = accelerateEndpoint + } +} + +// Hash materials provides relevant initialized hash algo writers +// based on the expected signature type. +// +// - For signature v4 request if the connection is insecure compute only sha256. +// - For signature v4 request if the connection is secure compute only md5. +// - For anonymous request compute md5. +func (c *Client) hashMaterials() (hashAlgos map[string]hash.Hash, hashSums map[string][]byte) { + hashSums = make(map[string][]byte) + hashAlgos = make(map[string]hash.Hash) + if c.overrideSignerType.IsV4() { + if c.secure { + hashAlgos["md5"] = md5.New() + } else { + hashAlgos["sha256"] = sha256.New() + } + } else { + if c.overrideSignerType.IsAnonymous() { + hashAlgos["md5"] = md5.New() + } + } + return hashAlgos, hashSums +} + +// requestMetadata - is container for all the values to make a request. +type requestMetadata struct { + // If set newRequest presigns the URL. + presignURL bool + + // User supplied. + bucketName string + objectName string + queryValues url.Values + customHeader http.Header + expires int64 + + // Generated by our internal code. + bucketLocation string + contentBody io.Reader + contentLength int64 + contentMD5Base64 string // carries base64 encoded md5sum + contentSHA256Hex string // carries hex encoded sha256sum +} + +// dumpHTTP - dump HTTP request and response. +func (c Client) dumpHTTP(req *http.Request, resp *http.Response) error { + // Starts http dump. + _, err := fmt.Fprintln(c.traceOutput, "---------START-HTTP---------") + if err != nil { + return err + } + + // Filter out Signature field from Authorization header. + origAuth := req.Header.Get("Authorization") + if origAuth != "" { + req.Header.Set("Authorization", redactSignature(origAuth)) + } + + // Only display request header. + reqTrace, err := httputil.DumpRequestOut(req, false) + if err != nil { + return err + } + + // Write request to trace output. + _, err = fmt.Fprint(c.traceOutput, string(reqTrace)) + if err != nil { + return err + } + + // Only display response header. + var respTrace []byte + + // For errors we make sure to dump response body as well. + if resp.StatusCode != http.StatusOK && + resp.StatusCode != http.StatusPartialContent && + resp.StatusCode != http.StatusNoContent { + respTrace, err = httputil.DumpResponse(resp, true) + if err != nil { + return err + } + } else { + respTrace, err = httputil.DumpResponse(resp, false) + if err != nil { + return err + } + } + + // Write response to trace output. + _, err = fmt.Fprint(c.traceOutput, strings.TrimSuffix(string(respTrace), "\r\n")) + if err != nil { + return err + } + + // Ends the http dump. + _, err = fmt.Fprintln(c.traceOutput, "---------END-HTTP---------") + if err != nil { + return err + } + + // Returns success. + return nil +} + +// do - execute http request. +func (c Client) do(req *http.Request) (*http.Response, error) { + resp, err := c.httpClient.Do(req) + if err != nil { + // Handle this specifically for now until future Golang versions fix this issue properly. + if urlErr, ok := err.(*url.Error); ok { + if strings.Contains(urlErr.Err.Error(), "EOF") { + return nil, &url.Error{ + Op: urlErr.Op, + URL: urlErr.URL, + Err: errors.New("Connection closed by foreign host " + urlErr.URL + ". Retry again."), + } + } + } + return nil, err + } + + // Response cannot be non-nil, report error if thats the case. + if resp == nil { + msg := "Response is empty. " + reportIssue + return nil, ErrInvalidArgument(msg) + } + + // If trace is enabled, dump http request and response. + if c.isTraceEnabled { + err = c.dumpHTTP(req, resp) + if err != nil { + return nil, err + } + } + + return resp, nil +} + +// List of success status. +var successStatus = []int{ + http.StatusOK, + http.StatusNoContent, + http.StatusPartialContent, +} + +// executeMethod - instantiates a given method, and retries the +// request upon any error up to maxRetries attempts in a binomially +// delayed manner using a standard back off algorithm. +func (c Client) executeMethod(ctx context.Context, method string, metadata requestMetadata) (res *http.Response, err error) { + var isRetryable bool // Indicates if request can be retried. + var bodySeeker io.Seeker // Extracted seeker from io.Reader. + var reqRetry = MaxRetry // Indicates how many times we can retry the request + + if metadata.contentBody != nil { + // Check if body is seekable then it is retryable. + bodySeeker, isRetryable = metadata.contentBody.(io.Seeker) + switch bodySeeker { + case os.Stdin, os.Stdout, os.Stderr: + isRetryable = false + } + // Retry only when reader is seekable + if !isRetryable { + reqRetry = 1 + } + + // Figure out if the body can be closed - if yes + // we will definitely close it upon the function + // return. + bodyCloser, ok := metadata.contentBody.(io.Closer) + if ok { + defer bodyCloser.Close() + } + } + + // Create a done channel to control 'newRetryTimer' go routine. + doneCh := make(chan struct{}, 1) + + // Indicate to our routine to exit cleanly upon return. + defer close(doneCh) + + // Blank indentifier is kept here on purpose since 'range' without + // blank identifiers is only supported since go1.4 + // https://golang.org/doc/go1.4#forrange. + for range c.newRetryTimer(reqRetry, DefaultRetryUnit, DefaultRetryCap, MaxJitter, doneCh) { + // Retry executes the following function body if request has an + // error until maxRetries have been exhausted, retry attempts are + // performed after waiting for a given period of time in a + // binomial fashion. + if isRetryable { + // Seek back to beginning for each attempt. + if _, err = bodySeeker.Seek(0, 0); err != nil { + // If seek failed, no need to retry. + return nil, err + } + } + + // Instantiate a new request. + var req *http.Request + req, err = c.newRequest(method, metadata) + if err != nil { + errResponse := ToErrorResponse(err) + if isS3CodeRetryable(errResponse.Code) { + continue // Retry. + } + return nil, err + } + + // Add context to request + req = req.WithContext(ctx) + + // Initiate the request. + res, err = c.do(req) + if err != nil { + // For supported http requests errors verify. + if isHTTPReqErrorRetryable(err) { + continue // Retry. + } + // For other errors, return here no need to retry. + return nil, err + } + + // For any known successful http status, return quickly. + for _, httpStatus := range successStatus { + if httpStatus == res.StatusCode { + return res, nil + } + } + + // Read the body to be saved later. + errBodyBytes, err := ioutil.ReadAll(res.Body) + // res.Body should be closed + closeResponse(res) + if err != nil { + return nil, err + } + + // Save the body. + errBodySeeker := bytes.NewReader(errBodyBytes) + res.Body = ioutil.NopCloser(errBodySeeker) + + // For errors verify if its retryable otherwise fail quickly. + errResponse := ToErrorResponse(httpRespToErrorResponse(res, metadata.bucketName, metadata.objectName)) + + // Save the body back again. + errBodySeeker.Seek(0, 0) // Seek back to starting point. + res.Body = ioutil.NopCloser(errBodySeeker) + + // Bucket region if set in error response and the error + // code dictates invalid region, we can retry the request + // with the new region. + // + // Additionally we should only retry if bucketLocation and custom + // region is empty. + if metadata.bucketLocation == "" && c.region == "" { + if errResponse.Code == "AuthorizationHeaderMalformed" || errResponse.Code == "InvalidRegion" { + if metadata.bucketName != "" && errResponse.Region != "" { + // Gather Cached location only if bucketName is present. + if _, cachedLocationError := c.bucketLocCache.Get(metadata.bucketName); cachedLocationError != false { + c.bucketLocCache.Set(metadata.bucketName, errResponse.Region) + continue // Retry. + } + } + } + } + + // Verify if error response code is retryable. + if isS3CodeRetryable(errResponse.Code) { + continue // Retry. + } + + // Verify if http status code is retryable. + if isHTTPStatusRetryable(res.StatusCode) { + continue // Retry. + } + + // For all other cases break out of the retry loop. + break + } + return res, err +} + +// newRequest - instantiate a new HTTP request for a given method. +func (c Client) newRequest(method string, metadata requestMetadata) (req *http.Request, err error) { + // If no method is supplied default to 'POST'. + if method == "" { + method = "POST" + } + + location := metadata.bucketLocation + if location == "" { + if metadata.bucketName != "" { + // Gather location only if bucketName is present. + location, err = c.getBucketLocation(metadata.bucketName) + if err != nil { + if ToErrorResponse(err).Code != "AccessDenied" { + return nil, err + } + } + // Upon AccessDenied error on fetching bucket location, default + // to possible locations based on endpoint URL. This can usually + // happen when GetBucketLocation() is disabled using IAM policies. + } + if location == "" { + location = getDefaultLocation(*c.endpointURL, c.region) + } + } + + // Look if target url supports virtual host. + isVirtualHost := c.isVirtualHostStyleRequest(*c.endpointURL, metadata.bucketName) + + // Construct a new target URL. + targetURL, err := c.makeTargetURL(metadata.bucketName, metadata.objectName, location, isVirtualHost, metadata.queryValues) + if err != nil { + return nil, err + } + + // Initialize a new HTTP request for the method. + req, err = http.NewRequest(method, targetURL.String(), nil) + if err != nil { + return nil, err + } + + // Get credentials from the configured credentials provider. + value, err := c.credsProvider.Get() + if err != nil { + return nil, err + } + + var ( + signerType = value.SignerType + accessKeyID = value.AccessKeyID + secretAccessKey = value.SecretAccessKey + sessionToken = value.SessionToken + ) + + // Custom signer set then override the behavior. + if c.overrideSignerType != credentials.SignatureDefault { + signerType = c.overrideSignerType + } + + // If signerType returned by credentials helper is anonymous, + // then do not sign regardless of signerType override. + if value.SignerType == credentials.SignatureAnonymous { + signerType = credentials.SignatureAnonymous + } + + // Generate presign url if needed, return right here. + if metadata.expires != 0 && metadata.presignURL { + if signerType.IsAnonymous() { + return nil, ErrInvalidArgument("Presigned URLs cannot be generated with anonymous credentials.") + } + if signerType.IsV2() { + // Presign URL with signature v2. + req = s3signer.PreSignV2(*req, accessKeyID, secretAccessKey, metadata.expires, isVirtualHost) + } else if signerType.IsV4() { + // Presign URL with signature v4. + req = s3signer.PreSignV4(*req, accessKeyID, secretAccessKey, sessionToken, location, metadata.expires) + } + return req, nil + } + + // Set 'User-Agent' header for the request. + c.setUserAgent(req) + + // Set all headers. + for k, v := range metadata.customHeader { + req.Header.Set(k, v[0]) + } + + // Go net/http notoriously closes the request body. + // - The request Body, if non-nil, will be closed by the underlying Transport, even on errors. + // This can cause underlying *os.File seekers to fail, avoid that + // by making sure to wrap the closer as a nop. + if metadata.contentLength == 0 { + req.Body = nil + } else { + req.Body = ioutil.NopCloser(metadata.contentBody) + } + + // Set incoming content-length. + req.ContentLength = metadata.contentLength + if req.ContentLength <= -1 { + // For unknown content length, we upload using transfer-encoding: chunked. + req.TransferEncoding = []string{"chunked"} + } + + // set md5Sum for content protection. + if len(metadata.contentMD5Base64) > 0 { + req.Header.Set("Content-Md5", metadata.contentMD5Base64) + } + + // For anonymous requests just return. + if signerType.IsAnonymous() { + return req, nil + } + + switch { + case signerType.IsV2(): + // Add signature version '2' authorization header. + req = s3signer.SignV2(*req, accessKeyID, secretAccessKey, isVirtualHost) + case metadata.objectName != "" && method == "PUT" && metadata.customHeader.Get("X-Amz-Copy-Source") == "" && !c.secure: + // Streaming signature is used by default for a PUT object request. Additionally we also + // look if the initialized client is secure, if yes then we don't need to perform + // streaming signature. + req = s3signer.StreamingSignV4(req, accessKeyID, + secretAccessKey, sessionToken, location, metadata.contentLength, time.Now().UTC()) + default: + // Set sha256 sum for signature calculation only with signature version '4'. + shaHeader := unsignedPayload + if metadata.contentSHA256Hex != "" { + shaHeader = metadata.contentSHA256Hex + } + req.Header.Set("X-Amz-Content-Sha256", shaHeader) + + // Add signature version '4' authorization header. + req = s3signer.SignV4(*req, accessKeyID, secretAccessKey, sessionToken, location) + } + + // Return request. + return req, nil +} + +// set User agent. +func (c Client) setUserAgent(req *http.Request) { + req.Header.Set("User-Agent", libraryUserAgent) + if c.appInfo.appName != "" && c.appInfo.appVersion != "" { + req.Header.Set("User-Agent", libraryUserAgent+" "+c.appInfo.appName+"/"+c.appInfo.appVersion) + } +} + +// makeTargetURL make a new target url. +func (c Client) makeTargetURL(bucketName, objectName, bucketLocation string, isVirtualHostStyle bool, queryValues url.Values) (*url.URL, error) { + host := c.endpointURL.Host + // For Amazon S3 endpoint, try to fetch location based endpoint. + if s3utils.IsAmazonEndpoint(*c.endpointURL) { + if c.s3AccelerateEndpoint != "" && bucketName != "" { + // http://docs.aws.amazon.com/AmazonS3/latest/dev/transfer-acceleration.html + // Disable transfer acceleration for non-compliant bucket names. + if strings.Contains(bucketName, ".") { + return nil, ErrTransferAccelerationBucket(bucketName) + } + // If transfer acceleration is requested set new host. + // For more details about enabling transfer acceleration read here. + // http://docs.aws.amazon.com/AmazonS3/latest/dev/transfer-acceleration.html + host = c.s3AccelerateEndpoint + } else { + // Do not change the host if the endpoint URL is a FIPS S3 endpoint. + if !s3utils.IsAmazonFIPSEndpoint(*c.endpointURL) { + // Fetch new host based on the bucket location. + host = getS3Endpoint(bucketLocation) + } + } + } + + // Save scheme. + scheme := c.endpointURL.Scheme + + // Strip port 80 and 443 so we won't send these ports in Host header. + // The reason is that browsers and curl automatically remove :80 and :443 + // with the generated presigned urls, then a signature mismatch error. + if h, p, err := net.SplitHostPort(host); err == nil { + if scheme == "http" && p == "80" || scheme == "https" && p == "443" { + host = h + } + } + + urlStr := scheme + "://" + host + "/" + // Make URL only if bucketName is available, otherwise use the + // endpoint URL. + if bucketName != "" { + // If endpoint supports virtual host style use that always. + // Currently only S3 and Google Cloud Storage would support + // virtual host style. + if isVirtualHostStyle { + urlStr = scheme + "://" + bucketName + "." + host + "/" + if objectName != "" { + urlStr = urlStr + s3utils.EncodePath(objectName) + } + } else { + // If not fall back to using path style. + urlStr = urlStr + bucketName + "/" + if objectName != "" { + urlStr = urlStr + s3utils.EncodePath(objectName) + } + } + } + + // If there are any query values, add them to the end. + if len(queryValues) > 0 { + urlStr = urlStr + "?" + s3utils.QueryEncode(queryValues) + } + + return url.Parse(urlStr) +} + +// returns true if virtual hosted style requests are to be used. +func (c *Client) isVirtualHostStyleRequest(url url.URL, bucketName string) bool { + if bucketName == "" { + return false + } + + if c.lookup == BucketLookupDNS { + return true + } + if c.lookup == BucketLookupPath { + return false + } + + // default to virtual only for Amazon/Google storage. In all other cases use + // path style requests + return s3utils.IsVirtualHostSupported(url, bucketName) +} diff --git a/vendor/github.com/minio/minio-go/appveyor.yml b/vendor/github.com/minio/minio-go/appveyor.yml new file mode 100644 index 0000000000000..48ea6e77dc046 --- /dev/null +++ b/vendor/github.com/minio/minio-go/appveyor.yml @@ -0,0 +1,39 @@ +# version format +version: "{build}" + +# Operating system (build VM template) +os: Windows Server 2012 R2 + +clone_folder: c:\gopath\src\github.com\minio\minio-go + +# environment variables +environment: + GOPATH: c:\gopath + GO15VENDOREXPERIMENT: 1 + +# scripts that run after cloning repository +install: + - set PATH=%GOPATH%\bin;c:\go\bin;%PATH% + - go version + - go env + - go get -u golang.org/x/lint/golint + - go get -u github.com/remyoudompheng/go-misc/deadcode + - go get -u github.com/gordonklaus/ineffassign + - go get -u golang.org/x/crypto/argon2 + - go get -t ./... + +# to run your custom scripts instead of automatic MSBuild +build_script: + - go vet ./... + - gofmt -s -l . + - golint -set_exit_status github.com/minio/minio-go... + - deadcode + - ineffassign . + - go test -short -v + - go test -short -race -v + +# to disable automatic tests +test: off + +# to disable deployment +deploy: off diff --git a/vendor/github.com/minio/minio-go/bucket-cache.go b/vendor/github.com/minio/minio-go/bucket-cache.go new file mode 100644 index 0000000000000..cac7ad7927cca --- /dev/null +++ b/vendor/github.com/minio/minio-go/bucket-cache.go @@ -0,0 +1,221 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2015-2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package minio + +import ( + "net/http" + "net/url" + "path" + "sync" + + "github.com/minio/minio-go/pkg/credentials" + "github.com/minio/minio-go/pkg/s3signer" + "github.com/minio/minio-go/pkg/s3utils" +) + +// bucketLocationCache - Provides simple mechanism to hold bucket +// locations in memory. +type bucketLocationCache struct { + // mutex is used for handling the concurrent + // read/write requests for cache. + sync.RWMutex + + // items holds the cached bucket locations. + items map[string]string +} + +// newBucketLocationCache - Provides a new bucket location cache to be +// used internally with the client object. +func newBucketLocationCache() *bucketLocationCache { + return &bucketLocationCache{ + items: make(map[string]string), + } +} + +// Get - Returns a value of a given key if it exists. +func (r *bucketLocationCache) Get(bucketName string) (location string, ok bool) { + r.RLock() + defer r.RUnlock() + location, ok = r.items[bucketName] + return +} + +// Set - Will persist a value into cache. +func (r *bucketLocationCache) Set(bucketName string, location string) { + r.Lock() + defer r.Unlock() + r.items[bucketName] = location +} + +// Delete - Deletes a bucket name from cache. +func (r *bucketLocationCache) Delete(bucketName string) { + r.Lock() + defer r.Unlock() + delete(r.items, bucketName) +} + +// GetBucketLocation - get location for the bucket name from location cache, if not +// fetch freshly by making a new request. +func (c Client) GetBucketLocation(bucketName string) (string, error) { + if err := s3utils.CheckValidBucketName(bucketName); err != nil { + return "", err + } + return c.getBucketLocation(bucketName) +} + +// getBucketLocation - Get location for the bucketName from location map cache, if not +// fetch freshly by making a new request. +func (c Client) getBucketLocation(bucketName string) (string, error) { + if err := s3utils.CheckValidBucketName(bucketName); err != nil { + return "", err + } + + // Region set then no need to fetch bucket location. + if c.region != "" { + return c.region, nil + } + + if location, ok := c.bucketLocCache.Get(bucketName); ok { + return location, nil + } + + // Initialize a new request. + req, err := c.getBucketLocationRequest(bucketName) + if err != nil { + return "", err + } + + // Initiate the request. + resp, err := c.do(req) + defer closeResponse(resp) + if err != nil { + return "", err + } + location, err := processBucketLocationResponse(resp, bucketName) + if err != nil { + return "", err + } + c.bucketLocCache.Set(bucketName, location) + return location, nil +} + +// processes the getBucketLocation http response from the server. +func processBucketLocationResponse(resp *http.Response, bucketName string) (bucketLocation string, err error) { + if resp != nil { + if resp.StatusCode != http.StatusOK { + err = httpRespToErrorResponse(resp, bucketName, "") + errResp := ToErrorResponse(err) + // For access denied error, it could be an anonymous + // request. Move forward and let the top level callers + // succeed if possible based on their policy. + if errResp.Code == "AccessDenied" { + return "us-east-1", nil + } + return "", err + } + } + + // Extract location. + var locationConstraint string + err = xmlDecoder(resp.Body, &locationConstraint) + if err != nil { + return "", err + } + + location := locationConstraint + // Location is empty will be 'us-east-1'. + if location == "" { + location = "us-east-1" + } + + // Location can be 'EU' convert it to meaningful 'eu-west-1'. + if location == "EU" { + location = "eu-west-1" + } + + // Save the location into cache. + + // Return. + return location, nil +} + +// getBucketLocationRequest - Wrapper creates a new getBucketLocation request. +func (c Client) getBucketLocationRequest(bucketName string) (*http.Request, error) { + // Set location query. + urlValues := make(url.Values) + urlValues.Set("location", "") + + // Set get bucket location always as path style. + targetURL := c.endpointURL + targetURL.Path = path.Join(bucketName, "") + "/" + targetURL.RawQuery = urlValues.Encode() + + // Get a new HTTP request for the method. + req, err := http.NewRequest("GET", targetURL.String(), nil) + if err != nil { + return nil, err + } + + // Set UserAgent for the request. + c.setUserAgent(req) + + // Get credentials from the configured credentials provider. + value, err := c.credsProvider.Get() + if err != nil { + return nil, err + } + + var ( + signerType = value.SignerType + accessKeyID = value.AccessKeyID + secretAccessKey = value.SecretAccessKey + sessionToken = value.SessionToken + ) + + // Custom signer set then override the behavior. + if c.overrideSignerType != credentials.SignatureDefault { + signerType = c.overrideSignerType + } + + // If signerType returned by credentials helper is anonymous, + // then do not sign regardless of signerType override. + if value.SignerType == credentials.SignatureAnonymous { + signerType = credentials.SignatureAnonymous + } + + if signerType.IsAnonymous() { + return req, nil + } + + if signerType.IsV2() { + // Get Bucket Location calls should be always path style + isVirtualHost := false + req = s3signer.SignV2(*req, accessKeyID, secretAccessKey, isVirtualHost) + return req, nil + } + + // Set sha256 sum for signature calculation only with signature version '4'. + contentSha256 := emptySHA256Hex + if c.secure { + contentSha256 = unsignedPayload + } + + req.Header.Set("X-Amz-Content-Sha256", contentSha256) + req = s3signer.SignV4(*req, accessKeyID, secretAccessKey, sessionToken, "us-east-1") + return req, nil +} diff --git a/vendor/github.com/minio/minio-go/bucket-notification.go b/vendor/github.com/minio/minio-go/bucket-notification.go new file mode 100644 index 0000000000000..ea303dd9dba74 --- /dev/null +++ b/vendor/github.com/minio/minio-go/bucket-notification.go @@ -0,0 +1,273 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2015-2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package minio + +import ( + "encoding/xml" + + "github.com/minio/minio-go/pkg/set" +) + +// NotificationEventType is a S3 notification event associated to the bucket notification configuration +type NotificationEventType string + +// The role of all event types are described in : +// http://docs.aws.amazon.com/AmazonS3/latest/dev/NotificationHowTo.html#notification-how-to-event-types-and-destinations +const ( + ObjectCreatedAll NotificationEventType = "s3:ObjectCreated:*" + ObjectCreatedPut = "s3:ObjectCreated:Put" + ObjectCreatedPost = "s3:ObjectCreated:Post" + ObjectCreatedCopy = "s3:ObjectCreated:Copy" + ObjectCreatedCompleteMultipartUpload = "s3:ObjectCreated:CompleteMultipartUpload" + ObjectAccessedGet = "s3:ObjectAccessed:Get" + ObjectAccessedHead = "s3:ObjectAccessed:Head" + ObjectAccessedAll = "s3:ObjectAccessed:*" + ObjectRemovedAll = "s3:ObjectRemoved:*" + ObjectRemovedDelete = "s3:ObjectRemoved:Delete" + ObjectRemovedDeleteMarkerCreated = "s3:ObjectRemoved:DeleteMarkerCreated" + ObjectReducedRedundancyLostObject = "s3:ReducedRedundancyLostObject" +) + +// FilterRule - child of S3Key, a tag in the notification xml which +// carries suffix/prefix filters +type FilterRule struct { + Name string `xml:"Name"` + Value string `xml:"Value"` +} + +// S3Key - child of Filter, a tag in the notification xml which +// carries suffix/prefix filters +type S3Key struct { + FilterRules []FilterRule `xml:"FilterRule,omitempty"` +} + +// Filter - a tag in the notification xml structure which carries +// suffix/prefix filters +type Filter struct { + S3Key S3Key `xml:"S3Key,omitempty"` +} + +// Arn - holds ARN information that will be sent to the web service, +// ARN desciption can be found in http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html +type Arn struct { + Partition string + Service string + Region string + AccountID string + Resource string +} + +// NewArn creates new ARN based on the given partition, service, region, account id and resource +func NewArn(partition, service, region, accountID, resource string) Arn { + return Arn{Partition: partition, + Service: service, + Region: region, + AccountID: accountID, + Resource: resource} +} + +// Return the string format of the ARN +func (arn Arn) String() string { + return "arn:" + arn.Partition + ":" + arn.Service + ":" + arn.Region + ":" + arn.AccountID + ":" + arn.Resource +} + +// NotificationConfig - represents one single notification configuration +// such as topic, queue or lambda configuration. +type NotificationConfig struct { + ID string `xml:"Id,omitempty"` + Arn Arn `xml:"-"` + Events []NotificationEventType `xml:"Event"` + Filter *Filter `xml:"Filter,omitempty"` +} + +// NewNotificationConfig creates one notification config and sets the given ARN +func NewNotificationConfig(arn Arn) NotificationConfig { + return NotificationConfig{Arn: arn, Filter: &Filter{}} +} + +// AddEvents adds one event to the current notification config +func (t *NotificationConfig) AddEvents(events ...NotificationEventType) { + t.Events = append(t.Events, events...) +} + +// AddFilterSuffix sets the suffix configuration to the current notification config +func (t *NotificationConfig) AddFilterSuffix(suffix string) { + if t.Filter == nil { + t.Filter = &Filter{} + } + newFilterRule := FilterRule{Name: "suffix", Value: suffix} + // Replace any suffix rule if existing and add to the list otherwise + for index := range t.Filter.S3Key.FilterRules { + if t.Filter.S3Key.FilterRules[index].Name == "suffix" { + t.Filter.S3Key.FilterRules[index] = newFilterRule + return + } + } + t.Filter.S3Key.FilterRules = append(t.Filter.S3Key.FilterRules, newFilterRule) +} + +// AddFilterPrefix sets the prefix configuration to the current notification config +func (t *NotificationConfig) AddFilterPrefix(prefix string) { + if t.Filter == nil { + t.Filter = &Filter{} + } + newFilterRule := FilterRule{Name: "prefix", Value: prefix} + // Replace any prefix rule if existing and add to the list otherwise + for index := range t.Filter.S3Key.FilterRules { + if t.Filter.S3Key.FilterRules[index].Name == "prefix" { + t.Filter.S3Key.FilterRules[index] = newFilterRule + return + } + } + t.Filter.S3Key.FilterRules = append(t.Filter.S3Key.FilterRules, newFilterRule) +} + +// TopicConfig carries one single topic notification configuration +type TopicConfig struct { + NotificationConfig + Topic string `xml:"Topic"` +} + +// QueueConfig carries one single queue notification configuration +type QueueConfig struct { + NotificationConfig + Queue string `xml:"Queue"` +} + +// LambdaConfig carries one single cloudfunction notification configuration +type LambdaConfig struct { + NotificationConfig + Lambda string `xml:"CloudFunction"` +} + +// BucketNotification - the struct that represents the whole XML to be sent to the web service +type BucketNotification struct { + XMLName xml.Name `xml:"NotificationConfiguration"` + LambdaConfigs []LambdaConfig `xml:"CloudFunctionConfiguration"` + TopicConfigs []TopicConfig `xml:"TopicConfiguration"` + QueueConfigs []QueueConfig `xml:"QueueConfiguration"` +} + +// AddTopic adds a given topic config to the general bucket notification config +func (b *BucketNotification) AddTopic(topicConfig NotificationConfig) bool { + newTopicConfig := TopicConfig{NotificationConfig: topicConfig, Topic: topicConfig.Arn.String()} + for _, n := range b.TopicConfigs { + // If new config matches existing one + if n.Topic == newTopicConfig.Arn.String() && newTopicConfig.Filter == n.Filter { + + existingConfig := set.NewStringSet() + for _, v := range n.Events { + existingConfig.Add(string(v)) + } + + newConfig := set.NewStringSet() + for _, v := range topicConfig.Events { + newConfig.Add(string(v)) + } + + if !newConfig.Intersection(existingConfig).IsEmpty() { + return false + } + } + } + b.TopicConfigs = append(b.TopicConfigs, newTopicConfig) + return true +} + +// AddQueue adds a given queue config to the general bucket notification config +func (b *BucketNotification) AddQueue(queueConfig NotificationConfig) bool { + newQueueConfig := QueueConfig{NotificationConfig: queueConfig, Queue: queueConfig.Arn.String()} + for _, n := range b.QueueConfigs { + if n.Queue == newQueueConfig.Arn.String() && newQueueConfig.Filter == n.Filter { + + existingConfig := set.NewStringSet() + for _, v := range n.Events { + existingConfig.Add(string(v)) + } + + newConfig := set.NewStringSet() + for _, v := range queueConfig.Events { + newConfig.Add(string(v)) + } + + if !newConfig.Intersection(existingConfig).IsEmpty() { + return false + } + } + } + b.QueueConfigs = append(b.QueueConfigs, newQueueConfig) + return true +} + +// AddLambda adds a given lambda config to the general bucket notification config +func (b *BucketNotification) AddLambda(lambdaConfig NotificationConfig) bool { + newLambdaConfig := LambdaConfig{NotificationConfig: lambdaConfig, Lambda: lambdaConfig.Arn.String()} + for _, n := range b.LambdaConfigs { + if n.Lambda == newLambdaConfig.Arn.String() && newLambdaConfig.Filter == n.Filter { + + existingConfig := set.NewStringSet() + for _, v := range n.Events { + existingConfig.Add(string(v)) + } + + newConfig := set.NewStringSet() + for _, v := range lambdaConfig.Events { + newConfig.Add(string(v)) + } + + if !newConfig.Intersection(existingConfig).IsEmpty() { + return false + } + } + } + b.LambdaConfigs = append(b.LambdaConfigs, newLambdaConfig) + return true +} + +// RemoveTopicByArn removes all topic configurations that match the exact specified ARN +func (b *BucketNotification) RemoveTopicByArn(arn Arn) { + var topics []TopicConfig + for _, topic := range b.TopicConfigs { + if topic.Topic != arn.String() { + topics = append(topics, topic) + } + } + b.TopicConfigs = topics +} + +// RemoveQueueByArn removes all queue configurations that match the exact specified ARN +func (b *BucketNotification) RemoveQueueByArn(arn Arn) { + var queues []QueueConfig + for _, queue := range b.QueueConfigs { + if queue.Queue != arn.String() { + queues = append(queues, queue) + } + } + b.QueueConfigs = queues +} + +// RemoveLambdaByArn removes all lambda configurations that match the exact specified ARN +func (b *BucketNotification) RemoveLambdaByArn(arn Arn) { + var lambdas []LambdaConfig + for _, lambda := range b.LambdaConfigs { + if lambda.Lambda != arn.String() { + lambdas = append(lambdas, lambda) + } + } + b.LambdaConfigs = lambdas +} diff --git a/vendor/github.com/minio/minio-go/constants.go b/vendor/github.com/minio/minio-go/constants.go new file mode 100644 index 0000000000000..737742318d9a2 --- /dev/null +++ b/vendor/github.com/minio/minio-go/constants.go @@ -0,0 +1,62 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2015-2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package minio + +/// Multipart upload defaults. + +// absMinPartSize - absolute minimum part size (5 MiB) below which +// a part in a multipart upload may not be uploaded. +const absMinPartSize = 1024 * 1024 * 5 + +// minPartSize - minimum part size 64MiB per object after which +// putObject behaves internally as multipart. +const minPartSize = 1024 * 1024 * 64 + +// maxPartsCount - maximum number of parts for a single multipart session. +const maxPartsCount = 10000 + +// maxPartSize - maximum part size 5GiB for a single multipart upload +// operation. +const maxPartSize = 1024 * 1024 * 1024 * 5 + +// maxSinglePutObjectSize - maximum size 5GiB of object per PUT +// operation. +const maxSinglePutObjectSize = 1024 * 1024 * 1024 * 5 + +// maxMultipartPutObjectSize - maximum size 5TiB of object for +// Multipart operation. +const maxMultipartPutObjectSize = 1024 * 1024 * 1024 * 1024 * 5 + +// unsignedPayload - value to be set to X-Amz-Content-Sha256 header when +// we don't want to sign the request payload +const unsignedPayload = "UNSIGNED-PAYLOAD" + +// Total number of parallel workers used for multipart operation. +const totalWorkers = 4 + +// Signature related constants. +const ( + signV4Algorithm = "AWS4-HMAC-SHA256" + iso8601DateFormat = "20060102T150405Z" +) + +// Storage class header constant. +const amzStorageClass = "X-Amz-Storage-Class" + +// Website redirect location header constant +const amzWebsiteRedirectLocation = "X-Amz-Website-Redirect-Location" diff --git a/vendor/github.com/minio/minio-go/core.go b/vendor/github.com/minio/minio-go/core.go new file mode 100644 index 0000000000000..4d51363f0d301 --- /dev/null +++ b/vendor/github.com/minio/minio-go/core.go @@ -0,0 +1,153 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2015-2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package minio + +import ( + "context" + "io" + "strings" + + "github.com/minio/minio-go/pkg/encrypt" +) + +// Core - Inherits Client and adds new methods to expose the low level S3 APIs. +type Core struct { + *Client +} + +// NewCore - Returns new initialized a Core client, this CoreClient should be +// only used under special conditions such as need to access lower primitives +// and being able to use them to write your own wrappers. +func NewCore(endpoint string, accessKeyID, secretAccessKey string, secure bool) (*Core, error) { + var s3Client Core + client, err := NewV4(endpoint, accessKeyID, secretAccessKey, secure) + if err != nil { + return nil, err + } + s3Client.Client = client + return &s3Client, nil +} + +// ListObjects - List all the objects at a prefix, optionally with marker and delimiter +// you can further filter the results. +func (c Core) ListObjects(bucket, prefix, marker, delimiter string, maxKeys int) (result ListBucketResult, err error) { + return c.listObjectsQuery(bucket, prefix, marker, delimiter, maxKeys) +} + +// ListObjectsV2 - Lists all the objects at a prefix, similar to ListObjects() but uses +// continuationToken instead of marker to support iteration over the results. +func (c Core) ListObjectsV2(bucketName, objectPrefix, continuationToken string, fetchOwner bool, delimiter string, maxkeys int, startAfter string) (ListBucketV2Result, error) { + return c.listObjectsV2Query(bucketName, objectPrefix, continuationToken, fetchOwner, delimiter, maxkeys, startAfter) +} + +// CopyObject - copies an object from source object to destination object on server side. +func (c Core) CopyObject(sourceBucket, sourceObject, destBucket, destObject string, metadata map[string]string) (ObjectInfo, error) { + return c.copyObjectDo(context.Background(), sourceBucket, sourceObject, destBucket, destObject, metadata) +} + +// CopyObjectPart - creates a part in a multipart upload by copying (a +// part of) an existing object. +func (c Core) CopyObjectPart(srcBucket, srcObject, destBucket, destObject string, uploadID string, + partID int, startOffset, length int64, metadata map[string]string) (p CompletePart, err error) { + + return c.copyObjectPartDo(context.Background(), srcBucket, srcObject, destBucket, destObject, uploadID, + partID, startOffset, length, metadata) +} + +// PutObject - Upload object. Uploads using single PUT call. +func (c Core) PutObject(bucket, object string, data io.Reader, size int64, md5Base64, sha256Hex string, metadata map[string]string, sse encrypt.ServerSide) (ObjectInfo, error) { + opts := PutObjectOptions{} + m := make(map[string]string) + for k, v := range metadata { + if strings.ToLower(k) == "content-encoding" { + opts.ContentEncoding = v + } else if strings.ToLower(k) == "content-disposition" { + opts.ContentDisposition = v + } else if strings.ToLower(k) == "content-language" { + opts.ContentLanguage = v + } else if strings.ToLower(k) == "content-type" { + opts.ContentType = v + } else if strings.ToLower(k) == "cache-control" { + opts.CacheControl = v + } else if strings.ToLower(k) == strings.ToLower(amzWebsiteRedirectLocation) { + opts.WebsiteRedirectLocation = v + } else { + m[k] = metadata[k] + } + } + opts.UserMetadata = m + opts.ServerSideEncryption = sse + return c.putObjectDo(context.Background(), bucket, object, data, md5Base64, sha256Hex, size, opts) +} + +// NewMultipartUpload - Initiates new multipart upload and returns the new uploadID. +func (c Core) NewMultipartUpload(bucket, object string, opts PutObjectOptions) (uploadID string, err error) { + result, err := c.initiateMultipartUpload(context.Background(), bucket, object, opts) + return result.UploadID, err +} + +// ListMultipartUploads - List incomplete uploads. +func (c Core) ListMultipartUploads(bucket, prefix, keyMarker, uploadIDMarker, delimiter string, maxUploads int) (result ListMultipartUploadsResult, err error) { + return c.listMultipartUploadsQuery(bucket, keyMarker, uploadIDMarker, prefix, delimiter, maxUploads) +} + +// PutObjectPart - Upload an object part. +func (c Core) PutObjectPart(bucket, object, uploadID string, partID int, data io.Reader, size int64, md5Base64, sha256Hex string, sse encrypt.ServerSide) (ObjectPart, error) { + return c.uploadPart(context.Background(), bucket, object, uploadID, data, partID, md5Base64, sha256Hex, size, sse) +} + +// ListObjectParts - List uploaded parts of an incomplete upload.x +func (c Core) ListObjectParts(bucket, object, uploadID string, partNumberMarker int, maxParts int) (result ListObjectPartsResult, err error) { + return c.listObjectPartsQuery(bucket, object, uploadID, partNumberMarker, maxParts) +} + +// CompleteMultipartUpload - Concatenate uploaded parts and commit to an object. +func (c Core) CompleteMultipartUpload(bucket, object, uploadID string, parts []CompletePart) (string, error) { + res, err := c.completeMultipartUpload(context.Background(), bucket, object, uploadID, completeMultipartUpload{ + Parts: parts, + }) + return res.ETag, err +} + +// AbortMultipartUpload - Abort an incomplete upload. +func (c Core) AbortMultipartUpload(bucket, object, uploadID string) error { + return c.abortMultipartUpload(context.Background(), bucket, object, uploadID) +} + +// GetBucketPolicy - fetches bucket access policy for a given bucket. +func (c Core) GetBucketPolicy(bucket string) (string, error) { + return c.getBucketPolicy(bucket) +} + +// PutBucketPolicy - applies a new bucket access policy for a given bucket. +func (c Core) PutBucketPolicy(bucket, bucketPolicy string) error { + return c.putBucketPolicy(bucket, bucketPolicy) +} + +// GetObject is a lower level API implemented to support reading +// partial objects and also downloading objects with special conditions +// matching etag, modtime etc. +func (c Core) GetObject(bucketName, objectName string, opts GetObjectOptions) (io.ReadCloser, ObjectInfo, error) { + return c.getObject(context.Background(), bucketName, objectName, opts) +} + +// StatObject is a lower level API implemented to support special +// conditions matching etag, modtime on a request. +func (c Core) StatObject(bucketName, objectName string, opts StatObjectOptions) (ObjectInfo, error) { + return c.statObject(context.Background(), bucketName, objectName, opts) +} diff --git a/vendor/github.com/minio/minio-go/hook-reader.go b/vendor/github.com/minio/minio-go/hook-reader.go new file mode 100644 index 0000000000000..8f32291d49b66 --- /dev/null +++ b/vendor/github.com/minio/minio-go/hook-reader.go @@ -0,0 +1,71 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2015-2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package minio + +import "io" + +// hookReader hooks additional reader in the source stream. It is +// useful for making progress bars. Second reader is appropriately +// notified about the exact number of bytes read from the primary +// source on each Read operation. +type hookReader struct { + source io.Reader + hook io.Reader +} + +// Seek implements io.Seeker. Seeks source first, and if necessary +// seeks hook if Seek method is appropriately found. +func (hr *hookReader) Seek(offset int64, whence int) (n int64, err error) { + // Verify for source has embedded Seeker, use it. + sourceSeeker, ok := hr.source.(io.Seeker) + if ok { + return sourceSeeker.Seek(offset, whence) + } + // Verify if hook has embedded Seeker, use it. + hookSeeker, ok := hr.hook.(io.Seeker) + if ok { + return hookSeeker.Seek(offset, whence) + } + return n, nil +} + +// Read implements io.Reader. Always reads from the source, the return +// value 'n' number of bytes are reported through the hook. Returns +// error for all non io.EOF conditions. +func (hr *hookReader) Read(b []byte) (n int, err error) { + n, err = hr.source.Read(b) + if err != nil && err != io.EOF { + return n, err + } + // Progress the hook with the total read bytes from the source. + if _, herr := hr.hook.Read(b[:n]); herr != nil { + if herr != io.EOF { + return n, herr + } + } + return n, err +} + +// newHook returns a io.ReadSeeker which implements hookReader that +// reports the data read from the source to the hook. +func newHook(source, hook io.Reader) io.Reader { + if hook == nil { + return source + } + return &hookReader{source, hook} +} diff --git a/vendor/github.com/minio/minio-go/pkg/credentials/chain.go b/vendor/github.com/minio/minio-go/pkg/credentials/chain.go new file mode 100644 index 0000000000000..e29826f480c48 --- /dev/null +++ b/vendor/github.com/minio/minio-go/pkg/credentials/chain.go @@ -0,0 +1,89 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package credentials + +// A Chain will search for a provider which returns credentials +// and cache that provider until Retrieve is called again. +// +// The Chain provides a way of chaining multiple providers together +// which will pick the first available using priority order of the +// Providers in the list. +// +// If none of the Providers retrieve valid credentials Value, ChainProvider's +// Retrieve() will return the no credentials value. +// +// If a Provider is found which returns valid credentials Value ChainProvider +// will cache that Provider for all calls to IsExpired(), until Retrieve is +// called again after IsExpired() is true. +// +// creds := credentials.NewChainCredentials( +// []credentials.Provider{ +// &credentials.EnvAWSS3{}, +// &credentials.EnvMinio{}, +// }) +// +// // Usage of ChainCredentials. +// mc, err := minio.NewWithCredentials(endpoint, creds, secure, "us-east-1") +// if err != nil { +// log.Fatalln(err) +// } +// +type Chain struct { + Providers []Provider + curr Provider +} + +// NewChainCredentials returns a pointer to a new Credentials object +// wrapping a chain of providers. +func NewChainCredentials(providers []Provider) *Credentials { + return New(&Chain{ + Providers: append([]Provider{}, providers...), + }) +} + +// Retrieve returns the credentials value, returns no credentials(anonymous) +// if no credentials provider returned any value. +// +// If a provider is found with credentials, it will be cached and any calls +// to IsExpired() will return the expired state of the cached provider. +func (c *Chain) Retrieve() (Value, error) { + for _, p := range c.Providers { + creds, _ := p.Retrieve() + // Always prioritize non-anonymous providers, if any. + if creds.AccessKeyID == "" && creds.SecretAccessKey == "" { + continue + } + c.curr = p + return creds, nil + } + // At this point we have exhausted all the providers and + // are left without any credentials return anonymous. + return Value{ + SignerType: SignatureAnonymous, + }, nil +} + +// IsExpired will returned the expired state of the currently cached provider +// if there is one. If there is no current provider, true will be returned. +func (c *Chain) IsExpired() bool { + if c.curr != nil { + return c.curr.IsExpired() + } + + return true +} diff --git a/vendor/github.com/minio/minio-go/pkg/credentials/config.json.sample b/vendor/github.com/minio/minio-go/pkg/credentials/config.json.sample new file mode 100644 index 0000000000000..130746f4baf5b --- /dev/null +++ b/vendor/github.com/minio/minio-go/pkg/credentials/config.json.sample @@ -0,0 +1,17 @@ +{ + "version": "8", + "hosts": { + "play": { + "url": "https://play.minio.io:9000", + "accessKey": "Q3AM3UQ867SPQQA43P2F", + "secretKey": "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG", + "api": "S3v2" + }, + "s3": { + "url": "https://s3.amazonaws.com", + "accessKey": "accessKey", + "secretKey": "secret", + "api": "S3v4" + } + } +} \ No newline at end of file diff --git a/vendor/github.com/minio/minio-go/pkg/credentials/credentials.go b/vendor/github.com/minio/minio-go/pkg/credentials/credentials.go new file mode 100644 index 0000000000000..4bfdad413cae5 --- /dev/null +++ b/vendor/github.com/minio/minio-go/pkg/credentials/credentials.go @@ -0,0 +1,175 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package credentials + +import ( + "sync" + "time" +) + +// A Value is the AWS credentials value for individual credential fields. +type Value struct { + // AWS Access key ID + AccessKeyID string + + // AWS Secret Access Key + SecretAccessKey string + + // AWS Session Token + SessionToken string + + // Signature Type. + SignerType SignatureType +} + +// A Provider is the interface for any component which will provide credentials +// Value. A provider is required to manage its own Expired state, and what to +// be expired means. +type Provider interface { + // Retrieve returns nil if it successfully retrieved the value. + // Error is returned if the value were not obtainable, or empty. + Retrieve() (Value, error) + + // IsExpired returns if the credentials are no longer valid, and need + // to be retrieved. + IsExpired() bool +} + +// A Expiry provides shared expiration logic to be used by credentials +// providers to implement expiry functionality. +// +// The best method to use this struct is as an anonymous field within the +// provider's struct. +// +// Example: +// type IAMCredentialProvider struct { +// Expiry +// ... +// } +type Expiry struct { + // The date/time when to expire on + expiration time.Time + + // If set will be used by IsExpired to determine the current time. + // Defaults to time.Now if CurrentTime is not set. + CurrentTime func() time.Time +} + +// SetExpiration sets the expiration IsExpired will check when called. +// +// If window is greater than 0 the expiration time will be reduced by the +// window value. +// +// Using a window is helpful to trigger credentials to expire sooner than +// the expiration time given to ensure no requests are made with expired +// tokens. +func (e *Expiry) SetExpiration(expiration time.Time, window time.Duration) { + e.expiration = expiration + if window > 0 { + e.expiration = e.expiration.Add(-window) + } +} + +// IsExpired returns if the credentials are expired. +func (e *Expiry) IsExpired() bool { + if e.CurrentTime == nil { + e.CurrentTime = time.Now + } + return e.expiration.Before(e.CurrentTime()) +} + +// Credentials - A container for synchronous safe retrieval of credentials Value. +// Credentials will cache the credentials value until they expire. Once the value +// expires the next Get will attempt to retrieve valid credentials. +// +// Credentials is safe to use across multiple goroutines and will manage the +// synchronous state so the Providers do not need to implement their own +// synchronization. +// +// The first Credentials.Get() will always call Provider.Retrieve() to get the +// first instance of the credentials Value. All calls to Get() after that +// will return the cached credentials Value until IsExpired() returns true. +type Credentials struct { + sync.Mutex + + creds Value + forceRefresh bool + provider Provider +} + +// New returns a pointer to a new Credentials with the provider set. +func New(provider Provider) *Credentials { + return &Credentials{ + provider: provider, + forceRefresh: true, + } +} + +// Get returns the credentials value, or error if the credentials Value failed +// to be retrieved. +// +// Will return the cached credentials Value if it has not expired. If the +// credentials Value has expired the Provider's Retrieve() will be called +// to refresh the credentials. +// +// If Credentials.Expire() was called the credentials Value will be force +// expired, and the next call to Get() will cause them to be refreshed. +func (c *Credentials) Get() (Value, error) { + c.Lock() + defer c.Unlock() + + if c.isExpired() { + creds, err := c.provider.Retrieve() + if err != nil { + return Value{}, err + } + c.creds = creds + c.forceRefresh = false + } + + return c.creds, nil +} + +// Expire expires the credentials and forces them to be retrieved on the +// next call to Get(). +// +// This will override the Provider's expired state, and force Credentials +// to call the Provider's Retrieve(). +func (c *Credentials) Expire() { + c.Lock() + defer c.Unlock() + + c.forceRefresh = true +} + +// IsExpired returns if the credentials are no longer valid, and need +// to be refreshed. +// +// If the Credentials were forced to be expired with Expire() this will +// reflect that override. +func (c *Credentials) IsExpired() bool { + c.Lock() + defer c.Unlock() + + return c.isExpired() +} + +// isExpired helper method wrapping the definition of expired credentials. +func (c *Credentials) isExpired() bool { + return c.forceRefresh || c.provider.IsExpired() +} diff --git a/vendor/github.com/minio/minio-go/pkg/credentials/credentials.sample b/vendor/github.com/minio/minio-go/pkg/credentials/credentials.sample new file mode 100644 index 0000000000000..7fc91d9d2047b --- /dev/null +++ b/vendor/github.com/minio/minio-go/pkg/credentials/credentials.sample @@ -0,0 +1,12 @@ +[default] +aws_access_key_id = accessKey +aws_secret_access_key = secret +aws_session_token = token + +[no_token] +aws_access_key_id = accessKey +aws_secret_access_key = secret + +[with_colon] +aws_access_key_id: accessKey +aws_secret_access_key: secret diff --git a/vendor/github.com/minio/minio-go/pkg/credentials/doc.go b/vendor/github.com/minio/minio-go/pkg/credentials/doc.go new file mode 100644 index 0000000000000..c48784ba865cc --- /dev/null +++ b/vendor/github.com/minio/minio-go/pkg/credentials/doc.go @@ -0,0 +1,62 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Package credentials provides credential retrieval and management +// for S3 compatible object storage. +// +// By default the Credentials.Get() will cache the successful result of a +// Provider's Retrieve() until Provider.IsExpired() returns true. At which +// point Credentials will call Provider's Retrieve() to get new credential Value. +// +// The Provider is responsible for determining when credentials have expired. +// It is also important to note that Credentials will always call Retrieve the +// first time Credentials.Get() is called. +// +// Example of using the environment variable credentials. +// +// creds := NewFromEnv() +// // Retrieve the credentials value +// credValue, err := creds.Get() +// if err != nil { +// // handle error +// } +// +// Example of forcing credentials to expire and be refreshed on the next Get(). +// This may be helpful to proactively expire credentials and refresh them sooner +// than they would naturally expire on their own. +// +// creds := NewFromIAM("") +// creds.Expire() +// credsValue, err := creds.Get() +// // New credentials will be retrieved instead of from cache. +// +// +// Custom Provider +// +// Each Provider built into this package also provides a helper method to generate +// a Credentials pointer setup with the provider. To use a custom Provider just +// create a type which satisfies the Provider interface and pass it to the +// NewCredentials method. +// +// type MyProvider struct{} +// func (m *MyProvider) Retrieve() (Value, error) {...} +// func (m *MyProvider) IsExpired() bool {...} +// +// creds := NewCredentials(&MyProvider{}) +// credValue, err := creds.Get() +// +package credentials diff --git a/vendor/github.com/minio/minio-go/pkg/credentials/env_aws.go b/vendor/github.com/minio/minio-go/pkg/credentials/env_aws.go new file mode 100644 index 0000000000000..f9b2cc33af870 --- /dev/null +++ b/vendor/github.com/minio/minio-go/pkg/credentials/env_aws.go @@ -0,0 +1,71 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package credentials + +import "os" + +// A EnvAWS retrieves credentials from the environment variables of the +// running process. EnvAWSironment credentials never expire. +// +// EnvAWSironment variables used: +// +// * Access Key ID: AWS_ACCESS_KEY_ID or AWS_ACCESS_KEY. +// * Secret Access Key: AWS_SECRET_ACCESS_KEY or AWS_SECRET_KEY. +// * Secret Token: AWS_SESSION_TOKEN. +type EnvAWS struct { + retrieved bool +} + +// NewEnvAWS returns a pointer to a new Credentials object +// wrapping the environment variable provider. +func NewEnvAWS() *Credentials { + return New(&EnvAWS{}) +} + +// Retrieve retrieves the keys from the environment. +func (e *EnvAWS) Retrieve() (Value, error) { + e.retrieved = false + + id := os.Getenv("AWS_ACCESS_KEY_ID") + if id == "" { + id = os.Getenv("AWS_ACCESS_KEY") + } + + secret := os.Getenv("AWS_SECRET_ACCESS_KEY") + if secret == "" { + secret = os.Getenv("AWS_SECRET_KEY") + } + + signerType := SignatureV4 + if id == "" || secret == "" { + signerType = SignatureAnonymous + } + + e.retrieved = true + return Value{ + AccessKeyID: id, + SecretAccessKey: secret, + SessionToken: os.Getenv("AWS_SESSION_TOKEN"), + SignerType: signerType, + }, nil +} + +// IsExpired returns if the credentials have been retrieved. +func (e *EnvAWS) IsExpired() bool { + return !e.retrieved +} diff --git a/vendor/github.com/minio/minio-go/pkg/credentials/env_minio.go b/vendor/github.com/minio/minio-go/pkg/credentials/env_minio.go new file mode 100644 index 0000000000000..d72e7718566eb --- /dev/null +++ b/vendor/github.com/minio/minio-go/pkg/credentials/env_minio.go @@ -0,0 +1,62 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package credentials + +import "os" + +// A EnvMinio retrieves credentials from the environment variables of the +// running process. EnvMinioironment credentials never expire. +// +// EnvMinioironment variables used: +// +// * Access Key ID: MINIO_ACCESS_KEY. +// * Secret Access Key: MINIO_SECRET_KEY. +type EnvMinio struct { + retrieved bool +} + +// NewEnvMinio returns a pointer to a new Credentials object +// wrapping the environment variable provider. +func NewEnvMinio() *Credentials { + return New(&EnvMinio{}) +} + +// Retrieve retrieves the keys from the environment. +func (e *EnvMinio) Retrieve() (Value, error) { + e.retrieved = false + + id := os.Getenv("MINIO_ACCESS_KEY") + secret := os.Getenv("MINIO_SECRET_KEY") + + signerType := SignatureV4 + if id == "" || secret == "" { + signerType = SignatureAnonymous + } + + e.retrieved = true + return Value{ + AccessKeyID: id, + SecretAccessKey: secret, + SignerType: signerType, + }, nil +} + +// IsExpired returns if the credentials have been retrieved. +func (e *EnvMinio) IsExpired() bool { + return !e.retrieved +} diff --git a/vendor/github.com/minio/minio-go/pkg/credentials/file_aws_credentials.go b/vendor/github.com/minio/minio-go/pkg/credentials/file_aws_credentials.go new file mode 100644 index 0000000000000..5ad68303a5616 --- /dev/null +++ b/vendor/github.com/minio/minio-go/pkg/credentials/file_aws_credentials.go @@ -0,0 +1,120 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package credentials + +import ( + "os" + "path/filepath" + + "github.com/go-ini/ini" + homedir "github.com/mitchellh/go-homedir" +) + +// A FileAWSCredentials retrieves credentials from the current user's home +// directory, and keeps track if those credentials are expired. +// +// Profile ini file example: $HOME/.aws/credentials +type FileAWSCredentials struct { + // Path to the shared credentials file. + // + // If empty will look for "AWS_SHARED_CREDENTIALS_FILE" env variable. If the + // env value is empty will default to current user's home directory. + // Linux/OSX: "$HOME/.aws/credentials" + // Windows: "%USERPROFILE%\.aws\credentials" + filename string + + // AWS Profile to extract credentials from the shared credentials file. If empty + // will default to environment variable "AWS_PROFILE" or "default" if + // environment variable is also not set. + profile string + + // retrieved states if the credentials have been successfully retrieved. + retrieved bool +} + +// NewFileAWSCredentials returns a pointer to a new Credentials object +// wrapping the Profile file provider. +func NewFileAWSCredentials(filename string, profile string) *Credentials { + return New(&FileAWSCredentials{ + filename: filename, + profile: profile, + }) +} + +// Retrieve reads and extracts the shared credentials from the current +// users home directory. +func (p *FileAWSCredentials) Retrieve() (Value, error) { + if p.filename == "" { + p.filename = os.Getenv("AWS_SHARED_CREDENTIALS_FILE") + if p.filename == "" { + homeDir, err := homedir.Dir() + if err != nil { + return Value{}, err + } + p.filename = filepath.Join(homeDir, ".aws", "credentials") + } + } + if p.profile == "" { + p.profile = os.Getenv("AWS_PROFILE") + if p.profile == "" { + p.profile = "default" + } + } + + p.retrieved = false + + iniProfile, err := loadProfile(p.filename, p.profile) + if err != nil { + return Value{}, err + } + + // Default to empty string if not found. + id := iniProfile.Key("aws_access_key_id") + // Default to empty string if not found. + secret := iniProfile.Key("aws_secret_access_key") + // Default to empty string if not found. + token := iniProfile.Key("aws_session_token") + + p.retrieved = true + return Value{ + AccessKeyID: id.String(), + SecretAccessKey: secret.String(), + SessionToken: token.String(), + SignerType: SignatureV4, + }, nil +} + +// IsExpired returns if the shared credentials have expired. +func (p *FileAWSCredentials) IsExpired() bool { + return !p.retrieved +} + +// loadProfiles loads from the file pointed to by shared credentials filename for profile. +// The credentials retrieved from the profile will be returned or error. Error will be +// returned if it fails to read from the file, or the data is invalid. +func loadProfile(filename, profile string) (*ini.Section, error) { + config, err := ini.Load(filename) + if err != nil { + return nil, err + } + iniProfile, err := config.GetSection(profile) + if err != nil { + return nil, err + } + return iniProfile, nil +} diff --git a/vendor/github.com/minio/minio-go/pkg/credentials/file_minio_client.go b/vendor/github.com/minio/minio-go/pkg/credentials/file_minio_client.go new file mode 100644 index 0000000000000..6a6827e3726e5 --- /dev/null +++ b/vendor/github.com/minio/minio-go/pkg/credentials/file_minio_client.go @@ -0,0 +1,133 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package credentials + +import ( + "encoding/json" + "io/ioutil" + "os" + "path/filepath" + "runtime" + + homedir "github.com/mitchellh/go-homedir" +) + +// A FileMinioClient retrieves credentials from the current user's home +// directory, and keeps track if those credentials are expired. +// +// Configuration file example: $HOME/.mc/config.json +type FileMinioClient struct { + // Path to the shared credentials file. + // + // If empty will look for "MINIO_SHARED_CREDENTIALS_FILE" env variable. If the + // env value is empty will default to current user's home directory. + // Linux/OSX: "$HOME/.mc/config.json" + // Windows: "%USERALIAS%\mc\config.json" + filename string + + // Minio Alias to extract credentials from the shared credentials file. If empty + // will default to environment variable "MINIO_ALIAS" or "default" if + // environment variable is also not set. + alias string + + // retrieved states if the credentials have been successfully retrieved. + retrieved bool +} + +// NewFileMinioClient returns a pointer to a new Credentials object +// wrapping the Alias file provider. +func NewFileMinioClient(filename string, alias string) *Credentials { + return New(&FileMinioClient{ + filename: filename, + alias: alias, + }) +} + +// Retrieve reads and extracts the shared credentials from the current +// users home directory. +func (p *FileMinioClient) Retrieve() (Value, error) { + if p.filename == "" { + if value, ok := os.LookupEnv("MINIO_SHARED_CREDENTIALS_FILE"); ok { + p.filename = value + } else { + homeDir, err := homedir.Dir() + if err != nil { + return Value{}, err + } + p.filename = filepath.Join(homeDir, ".mc", "config.json") + if runtime.GOOS == "windows" { + p.filename = filepath.Join(homeDir, "mc", "config.json") + } + } + } + + if p.alias == "" { + p.alias = os.Getenv("MINIO_ALIAS") + if p.alias == "" { + p.alias = "s3" + } + } + + p.retrieved = false + + hostCfg, err := loadAlias(p.filename, p.alias) + if err != nil { + return Value{}, err + } + + p.retrieved = true + return Value{ + AccessKeyID: hostCfg.AccessKey, + SecretAccessKey: hostCfg.SecretKey, + SignerType: parseSignatureType(hostCfg.API), + }, nil +} + +// IsExpired returns if the shared credentials have expired. +func (p *FileMinioClient) IsExpired() bool { + return !p.retrieved +} + +// hostConfig configuration of a host. +type hostConfig struct { + URL string `json:"url"` + AccessKey string `json:"accessKey"` + SecretKey string `json:"secretKey"` + API string `json:"api"` +} + +// config config version. +type config struct { + Version string `json:"version"` + Hosts map[string]hostConfig `json:"hosts"` +} + +// loadAliass loads from the file pointed to by shared credentials filename for alias. +// The credentials retrieved from the alias will be returned or error. Error will be +// returned if it fails to read from the file. +func loadAlias(filename, alias string) (hostConfig, error) { + cfg := &config{} + configBytes, err := ioutil.ReadFile(filename) + if err != nil { + return hostConfig{}, err + } + if err = json.Unmarshal(configBytes, cfg); err != nil { + return hostConfig{}, err + } + return cfg.Hosts[alias], nil +} diff --git a/vendor/github.com/minio/minio-go/pkg/credentials/iam_aws.go b/vendor/github.com/minio/minio-go/pkg/credentials/iam_aws.go new file mode 100644 index 0000000000000..05b2a8bb487c0 --- /dev/null +++ b/vendor/github.com/minio/minio-go/pkg/credentials/iam_aws.go @@ -0,0 +1,250 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package credentials + +import ( + "bufio" + "encoding/json" + "errors" + "fmt" + "net/http" + "net/url" + "os" + "path" + "time" +) + +// DefaultExpiryWindow - Default expiry window. +// ExpiryWindow will allow the credentials to trigger refreshing +// prior to the credentials actually expiring. This is beneficial +// so race conditions with expiring credentials do not cause +// request to fail unexpectedly due to ExpiredTokenException exceptions. +const DefaultExpiryWindow = time.Second * 10 // 10 secs + +// A IAM retrieves credentials from the EC2 service, and keeps track if +// those credentials are expired. +type IAM struct { + Expiry + + // Required http Client to use when connecting to IAM metadata service. + Client *http.Client + + // Custom endpoint to fetch IAM role credentials. + endpoint string +} + +// IAM Roles for Amazon EC2 +// http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html +const ( + defaultIAMRoleEndpoint = "http://169.254.169.254" + defaultECSRoleEndpoint = "http://169.254.170.2" + defaultIAMSecurityCredsPath = "/latest/meta-data/iam/security-credentials" +) + +// https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-iam-roles.html +func getEndpoint(endpoint string) (string, bool) { + if endpoint != "" { + return endpoint, os.Getenv("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI") != "" + } + if ecsURI := os.Getenv("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"); ecsURI != "" { + return fmt.Sprintf("%s%s", defaultECSRoleEndpoint, ecsURI), true + } + return defaultIAMRoleEndpoint, false +} + +// NewIAM returns a pointer to a new Credentials object wrapping the IAM. +func NewIAM(endpoint string) *Credentials { + p := &IAM{ + Client: &http.Client{ + Transport: http.DefaultTransport, + }, + endpoint: endpoint, + } + return New(p) +} + +// Retrieve retrieves credentials from the EC2 service. +// Error will be returned if the request fails, or unable to extract +// the desired +func (m *IAM) Retrieve() (Value, error) { + endpoint, isEcsTask := getEndpoint(m.endpoint) + var roleCreds ec2RoleCredRespBody + var err error + if isEcsTask { + roleCreds, err = getEcsTaskCredentials(m.Client, endpoint) + } else { + roleCreds, err = getCredentials(m.Client, endpoint) + } + if err != nil { + return Value{}, err + } + // Expiry window is set to 10secs. + m.SetExpiration(roleCreds.Expiration, DefaultExpiryWindow) + + return Value{ + AccessKeyID: roleCreds.AccessKeyID, + SecretAccessKey: roleCreds.SecretAccessKey, + SessionToken: roleCreds.Token, + SignerType: SignatureV4, + }, nil +} + +// A ec2RoleCredRespBody provides the shape for unmarshaling credential +// request responses. +type ec2RoleCredRespBody struct { + // Success State + Expiration time.Time + AccessKeyID string + SecretAccessKey string + Token string + + // Error state + Code string + Message string + + // Unused params. + LastUpdated time.Time + Type string +} + +// Get the final IAM role URL where the request will +// be sent to fetch the rolling access credentials. +// http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html +func getIAMRoleURL(endpoint string) (*url.URL, error) { + u, err := url.Parse(endpoint) + if err != nil { + return nil, err + } + u.Path = defaultIAMSecurityCredsPath + return u, nil +} + +// listRoleNames lists of credential role names associated +// with the current EC2 service. If there are no credentials, +// or there is an error making or receiving the request. +// http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html +func listRoleNames(client *http.Client, u *url.URL) ([]string, error) { + req, err := http.NewRequest("GET", u.String(), nil) + if err != nil { + return nil, err + } + resp, err := client.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return nil, errors.New(resp.Status) + } + + credsList := []string{} + s := bufio.NewScanner(resp.Body) + for s.Scan() { + credsList = append(credsList, s.Text()) + } + + if err := s.Err(); err != nil { + return nil, err + } + + return credsList, nil +} + +func getEcsTaskCredentials(client *http.Client, endpoint string) (ec2RoleCredRespBody, error) { + req, err := http.NewRequest("GET", endpoint, nil) + if err != nil { + return ec2RoleCredRespBody{}, err + } + + resp, err := client.Do(req) + if err != nil { + return ec2RoleCredRespBody{}, err + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return ec2RoleCredRespBody{}, errors.New(resp.Status) + } + + respCreds := ec2RoleCredRespBody{} + if err := json.NewDecoder(resp.Body).Decode(&respCreds); err != nil { + return ec2RoleCredRespBody{}, err + } + + return respCreds, nil +} + +// getCredentials - obtains the credentials from the IAM role name associated with +// the current EC2 service. +// +// If the credentials cannot be found, or there is an error +// reading the response an error will be returned. +func getCredentials(client *http.Client, endpoint string) (ec2RoleCredRespBody, error) { + + // http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html + u, err := getIAMRoleURL(endpoint) + if err != nil { + return ec2RoleCredRespBody{}, err + } + + // http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html + roleNames, err := listRoleNames(client, u) + if err != nil { + return ec2RoleCredRespBody{}, err + } + + if len(roleNames) == 0 { + return ec2RoleCredRespBody{}, errors.New("No IAM roles attached to this EC2 service") + } + + // http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html + // - An instance profile can contain only one IAM role. This limit cannot be increased. + roleName := roleNames[0] + + // http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html + // The following command retrieves the security credentials for an + // IAM role named `s3access`. + // + // $ curl http://169.254.169.254/latest/meta-data/iam/security-credentials/s3access + // + u.Path = path.Join(u.Path, roleName) + req, err := http.NewRequest("GET", u.String(), nil) + if err != nil { + return ec2RoleCredRespBody{}, err + } + + resp, err := client.Do(req) + if err != nil { + return ec2RoleCredRespBody{}, err + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return ec2RoleCredRespBody{}, errors.New(resp.Status) + } + + respCreds := ec2RoleCredRespBody{} + if err := json.NewDecoder(resp.Body).Decode(&respCreds); err != nil { + return ec2RoleCredRespBody{}, err + } + + if respCreds.Code != "Success" { + // If an error code was returned something failed requesting the role. + return ec2RoleCredRespBody{}, errors.New(respCreds.Message) + } + + return respCreds, nil +} diff --git a/vendor/github.com/minio/minio-go/pkg/credentials/signature-type.go b/vendor/github.com/minio/minio-go/pkg/credentials/signature-type.go new file mode 100644 index 0000000000000..1b768e8c3218b --- /dev/null +++ b/vendor/github.com/minio/minio-go/pkg/credentials/signature-type.go @@ -0,0 +1,77 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package credentials + +import "strings" + +// SignatureType is type of Authorization requested for a given HTTP request. +type SignatureType int + +// Different types of supported signatures - default is SignatureV4 or SignatureDefault. +const ( + // SignatureDefault is always set to v4. + SignatureDefault SignatureType = iota + SignatureV4 + SignatureV2 + SignatureV4Streaming + SignatureAnonymous // Anonymous signature signifies, no signature. +) + +// IsV2 - is signature SignatureV2? +func (s SignatureType) IsV2() bool { + return s == SignatureV2 +} + +// IsV4 - is signature SignatureV4? +func (s SignatureType) IsV4() bool { + return s == SignatureV4 || s == SignatureDefault +} + +// IsStreamingV4 - is signature SignatureV4Streaming? +func (s SignatureType) IsStreamingV4() bool { + return s == SignatureV4Streaming +} + +// IsAnonymous - is signature empty? +func (s SignatureType) IsAnonymous() bool { + return s == SignatureAnonymous +} + +// Stringer humanized version of signature type, +// strings returned here are case insensitive. +func (s SignatureType) String() string { + if s.IsV2() { + return "S3v2" + } else if s.IsV4() { + return "S3v4" + } else if s.IsStreamingV4() { + return "S3v4Streaming" + } + return "Anonymous" +} + +func parseSignatureType(str string) SignatureType { + if strings.EqualFold(str, "S3v4") { + return SignatureV4 + } else if strings.EqualFold(str, "S3v2") { + return SignatureV2 + } else if strings.EqualFold(str, "S3v4Streaming") { + return SignatureV4Streaming + } + return SignatureAnonymous +} diff --git a/vendor/github.com/minio/minio-go/pkg/credentials/static.go b/vendor/github.com/minio/minio-go/pkg/credentials/static.go new file mode 100644 index 0000000000000..8b0ba711cb28f --- /dev/null +++ b/vendor/github.com/minio/minio-go/pkg/credentials/static.go @@ -0,0 +1,67 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package credentials + +// A Static is a set of credentials which are set programmatically, +// and will never expire. +type Static struct { + Value +} + +// NewStaticV2 returns a pointer to a new Credentials object +// wrapping a static credentials value provider, signature is +// set to v2. If access and secret are not specified then +// regardless of signature type set it Value will return +// as anonymous. +func NewStaticV2(id, secret, token string) *Credentials { + return NewStatic(id, secret, token, SignatureV2) +} + +// NewStaticV4 is similar to NewStaticV2 with similar considerations. +func NewStaticV4(id, secret, token string) *Credentials { + return NewStatic(id, secret, token, SignatureV4) +} + +// NewStatic returns a pointer to a new Credentials object +// wrapping a static credentials value provider. +func NewStatic(id, secret, token string, signerType SignatureType) *Credentials { + return New(&Static{ + Value: Value{ + AccessKeyID: id, + SecretAccessKey: secret, + SessionToken: token, + SignerType: signerType, + }, + }) +} + +// Retrieve returns the static credentials. +func (s *Static) Retrieve() (Value, error) { + if s.AccessKeyID == "" || s.SecretAccessKey == "" { + // Anonymous is not an error + return Value{SignerType: SignatureAnonymous}, nil + } + return s.Value, nil +} + +// IsExpired returns if the credentials are expired. +// +// For Static, the credentials never expired. +func (s *Static) IsExpired() bool { + return false +} diff --git a/vendor/github.com/minio/minio-go/pkg/credentials/sts_client_grants.go b/vendor/github.com/minio/minio-go/pkg/credentials/sts_client_grants.go new file mode 100644 index 0000000000000..f0a4e8d2c80bd --- /dev/null +++ b/vendor/github.com/minio/minio-go/pkg/credentials/sts_client_grants.go @@ -0,0 +1,173 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2019 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package credentials + +import ( + "encoding/xml" + "errors" + "fmt" + "net/http" + "net/url" + "time" +) + +// AssumedRoleUser - The identifiers for the temporary security credentials that +// the operation returns. Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumedRoleUser +type AssumedRoleUser struct { + Arn string + AssumedRoleID string `xml:"AssumeRoleId"` +} + +// AssumeRoleWithClientGrantsResponse contains the result of successful AssumeRoleWithClientGrants request. +type AssumeRoleWithClientGrantsResponse struct { + XMLName xml.Name `xml:"https://sts.amazonaws.com/doc/2011-06-15/ AssumeRoleWithClientGrantsResponse" json:"-"` + Result ClientGrantsResult `xml:"AssumeRoleWithClientGrantsResult"` + ResponseMetadata struct { + RequestID string `xml:"RequestId,omitempty"` + } `xml:"ResponseMetadata,omitempty"` +} + +// ClientGrantsResult - Contains the response to a successful AssumeRoleWithClientGrants +// request, including temporary credentials that can be used to make Minio API requests. +type ClientGrantsResult struct { + AssumedRoleUser AssumedRoleUser `xml:",omitempty"` + Audience string `xml:",omitempty"` + Credentials struct { + AccessKey string `xml:"AccessKeyId" json:"accessKey,omitempty"` + SecretKey string `xml:"SecretAccessKey" json:"secretKey,omitempty"` + Expiration time.Time `xml:"Expiration" json:"expiration,omitempty"` + SessionToken string `xml:"SessionToken" json:"sessionToken,omitempty"` + } `xml:",omitempty"` + PackedPolicySize int `xml:",omitempty"` + Provider string `xml:",omitempty"` + SubjectFromClientGrantsToken string `xml:",omitempty"` +} + +// ClientGrantsToken - client grants token with expiry. +type ClientGrantsToken struct { + token string + expiry int +} + +// Token - access token returned after authenticating client grants. +func (c *ClientGrantsToken) Token() string { + return c.token +} + +// Expiry - expiry for the access token returned after authenticating +// client grants. +func (c *ClientGrantsToken) Expiry() string { + return fmt.Sprintf("%d", c.expiry) +} + +// A STSClientGrants retrieves credentials from Minio service, and keeps track if +// those credentials are expired. +type STSClientGrants struct { + Expiry + + // Required http Client to use when connecting to Minio STS service. + Client *http.Client + + // Minio endpoint to fetch STS credentials. + stsEndpoint string + + // getClientGrantsTokenExpiry function to retrieve tokens + // from IDP This function should return two values one is + // accessToken which is a self contained access token (JWT) + // and second return value is the expiry associated with + // this token. This is a customer provided function and + // is mandatory. + getClientGrantsTokenExpiry func() (*ClientGrantsToken, error) +} + +// NewSTSClientGrants returns a pointer to a new +// Credentials object wrapping the STSClientGrants. +func NewSTSClientGrants(stsEndpoint string, getClientGrantsTokenExpiry func() (*ClientGrantsToken, error)) (*Credentials, error) { + if stsEndpoint == "" { + return nil, errors.New("STS endpoint cannot be empty") + } + if getClientGrantsTokenExpiry == nil { + return nil, errors.New("Client grants access token and expiry retrieval function should be defined") + } + return New(&STSClientGrants{ + Client: &http.Client{ + Transport: http.DefaultTransport, + }, + stsEndpoint: stsEndpoint, + getClientGrantsTokenExpiry: getClientGrantsTokenExpiry, + }), nil +} + +func getClientGrantsCredentials(clnt *http.Client, endpoint string, + getClientGrantsTokenExpiry func() (*ClientGrantsToken, error)) (AssumeRoleWithClientGrantsResponse, error) { + + accessToken, err := getClientGrantsTokenExpiry() + if err != nil { + return AssumeRoleWithClientGrantsResponse{}, err + } + + v := url.Values{} + v.Set("Action", "AssumeRoleWithClientGrants") + v.Set("Token", accessToken.Token()) + v.Set("DurationSeconds", accessToken.Expiry()) + v.Set("Version", "2011-06-15") + + u, err := url.Parse(endpoint) + if err != nil { + return AssumeRoleWithClientGrantsResponse{}, err + } + u.RawQuery = v.Encode() + + req, err := http.NewRequest("POST", u.String(), nil) + if err != nil { + return AssumeRoleWithClientGrantsResponse{}, err + } + resp, err := clnt.Do(req) + if err != nil { + return AssumeRoleWithClientGrantsResponse{}, err + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return AssumeRoleWithClientGrantsResponse{}, errors.New(resp.Status) + } + + a := AssumeRoleWithClientGrantsResponse{} + if err = xml.NewDecoder(resp.Body).Decode(&a); err != nil { + return AssumeRoleWithClientGrantsResponse{}, err + } + return a, nil +} + +// Retrieve retrieves credentials from the Minio service. +// Error will be returned if the request fails. +func (m *STSClientGrants) Retrieve() (Value, error) { + a, err := getClientGrantsCredentials(m.Client, m.stsEndpoint, m.getClientGrantsTokenExpiry) + if err != nil { + return Value{}, err + } + + // Expiry window is set to 10secs. + m.SetExpiration(a.Result.Credentials.Expiration, DefaultExpiryWindow) + + return Value{ + AccessKeyID: a.Result.Credentials.AccessKey, + SecretAccessKey: a.Result.Credentials.SecretKey, + SessionToken: a.Result.Credentials.SessionToken, + SignerType: SignatureV4, + }, nil +} diff --git a/vendor/github.com/minio/minio-go/pkg/credentials/sts_web_identity.go b/vendor/github.com/minio/minio-go/pkg/credentials/sts_web_identity.go new file mode 100644 index 0000000000000..d924b16c7ebca --- /dev/null +++ b/vendor/github.com/minio/minio-go/pkg/credentials/sts_web_identity.go @@ -0,0 +1,169 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2019 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package credentials + +import ( + "encoding/xml" + "errors" + "fmt" + "net/http" + "net/url" + "time" +) + +// AssumeRoleWithWebIdentityResponse contains the result of successful AssumeRoleWithWebIdentity request. +type AssumeRoleWithWebIdentityResponse struct { + XMLName xml.Name `xml:"https://sts.amazonaws.com/doc/2011-06-15/ AssumeRoleWithWebIdentityResponse" json:"-"` + Result WebIdentityResult `xml:"AssumeRoleWithWebIdentityResult"` + ResponseMetadata struct { + RequestID string `xml:"RequestId,omitempty"` + } `xml:"ResponseMetadata,omitempty"` +} + +// WebIdentityResult - Contains the response to a successful AssumeRoleWithWebIdentity +// request, including temporary credentials that can be used to make Minio API requests. +type WebIdentityResult struct { + AssumedRoleUser AssumedRoleUser `xml:",omitempty"` + Audience string `xml:",omitempty"` + Credentials struct { + AccessKey string `xml:"AccessKeyId" json:"accessKey,omitempty"` + SecretKey string `xml:"SecretAccessKey" json:"secretKey,omitempty"` + Expiration time.Time `xml:"Expiration" json:"expiration,omitempty"` + SessionToken string `xml:"SessionToken" json:"sessionToken,omitempty"` + } `xml:",omitempty"` + PackedPolicySize int `xml:",omitempty"` + Provider string `xml:",omitempty"` + SubjectFromWebIdentityToken string `xml:",omitempty"` +} + +// WebIdentityToken - web identity token with expiry. +type WebIdentityToken struct { + token string + expiry int +} + +// Token - access token returned after authenticating web identity. +func (c *WebIdentityToken) Token() string { + return c.token +} + +// Expiry - expiry for the access token returned after authenticating +// web identity. +func (c *WebIdentityToken) Expiry() string { + return fmt.Sprintf("%d", c.expiry) +} + +// A STSWebIdentity retrieves credentials from Minio service, and keeps track if +// those credentials are expired. +type STSWebIdentity struct { + Expiry + + // Required http Client to use when connecting to Minio STS service. + Client *http.Client + + // Minio endpoint to fetch STS credentials. + stsEndpoint string + + // getWebIDTokenExpiry function which returns ID tokens + // from IDP. This function should return two values one + // is ID token which is a self contained ID token (JWT) + // and second return value is the expiry associated with + // this token. + // This is a customer provided function and is mandatory. + getWebIDTokenExpiry func() (*WebIdentityToken, error) +} + +// NewSTSWebIdentity returns a pointer to a new +// Credentials object wrapping the STSWebIdentity. +func NewSTSWebIdentity(stsEndpoint string, getWebIDTokenExpiry func() (*WebIdentityToken, error)) (*Credentials, error) { + if stsEndpoint == "" { + return nil, errors.New("STS endpoint cannot be empty") + } + if getWebIDTokenExpiry == nil { + return nil, errors.New("Web ID token and expiry retrieval function should be defined") + } + return New(&STSWebIdentity{ + Client: &http.Client{ + Transport: http.DefaultTransport, + }, + stsEndpoint: stsEndpoint, + getWebIDTokenExpiry: getWebIDTokenExpiry, + }), nil +} + +func getWebIdentityCredentials(clnt *http.Client, endpoint string, + getWebIDTokenExpiry func() (*WebIdentityToken, error)) (AssumeRoleWithWebIdentityResponse, error) { + idToken, err := getWebIDTokenExpiry() + if err != nil { + return AssumeRoleWithWebIdentityResponse{}, err + } + + v := url.Values{} + v.Set("Action", "AssumeRoleWithWebIdentity") + v.Set("WebIdentityToken", idToken.Token()) + v.Set("DurationSeconds", idToken.Expiry()) + v.Set("Version", "2011-06-15") + + u, err := url.Parse(endpoint) + if err != nil { + return AssumeRoleWithWebIdentityResponse{}, err + } + + u.RawQuery = v.Encode() + + req, err := http.NewRequest("POST", u.String(), nil) + if err != nil { + return AssumeRoleWithWebIdentityResponse{}, err + } + + resp, err := clnt.Do(req) + if err != nil { + return AssumeRoleWithWebIdentityResponse{}, err + } + + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return AssumeRoleWithWebIdentityResponse{}, errors.New(resp.Status) + } + + a := AssumeRoleWithWebIdentityResponse{} + if err = xml.NewDecoder(resp.Body).Decode(&a); err != nil { + return AssumeRoleWithWebIdentityResponse{}, err + } + + return a, nil +} + +// Retrieve retrieves credentials from the Minio service. +// Error will be returned if the request fails. +func (m *STSWebIdentity) Retrieve() (Value, error) { + a, err := getWebIdentityCredentials(m.Client, m.stsEndpoint, m.getWebIDTokenExpiry) + if err != nil { + return Value{}, err + } + + // Expiry window is set to 10secs. + m.SetExpiration(a.Result.Credentials.Expiration, DefaultExpiryWindow) + + return Value{ + AccessKeyID: a.Result.Credentials.AccessKey, + SecretAccessKey: a.Result.Credentials.SecretKey, + SessionToken: a.Result.Credentials.SessionToken, + SignerType: SignatureV4, + }, nil +} diff --git a/vendor/github.com/minio/minio-go/pkg/encrypt/server-side.go b/vendor/github.com/minio/minio-go/pkg/encrypt/server-side.go new file mode 100644 index 0000000000000..2d3c70f0022fd --- /dev/null +++ b/vendor/github.com/minio/minio-go/pkg/encrypt/server-side.go @@ -0,0 +1,195 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2018 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package encrypt + +import ( + "crypto/md5" + "encoding/base64" + "encoding/json" + "errors" + "net/http" + + "golang.org/x/crypto/argon2" +) + +const ( + // sseGenericHeader is the AWS SSE header used for SSE-S3 and SSE-KMS. + sseGenericHeader = "X-Amz-Server-Side-Encryption" + + // sseKmsKeyID is the AWS SSE-KMS key id. + sseKmsKeyID = sseGenericHeader + "-Aws-Kms-Key-Id" + // sseEncryptionContext is the AWS SSE-KMS Encryption Context data. + sseEncryptionContext = sseGenericHeader + "-Encryption-Context" + + // sseCustomerAlgorithm is the AWS SSE-C algorithm HTTP header key. + sseCustomerAlgorithm = sseGenericHeader + "-Customer-Algorithm" + // sseCustomerKey is the AWS SSE-C encryption key HTTP header key. + sseCustomerKey = sseGenericHeader + "-Customer-Key" + // sseCustomerKeyMD5 is the AWS SSE-C encryption key MD5 HTTP header key. + sseCustomerKeyMD5 = sseGenericHeader + "-Customer-Key-MD5" + + // sseCopyCustomerAlgorithm is the AWS SSE-C algorithm HTTP header key for CopyObject API. + sseCopyCustomerAlgorithm = "X-Amz-Copy-Source-Server-Side-Encryption-Customer-Algorithm" + // sseCopyCustomerKey is the AWS SSE-C encryption key HTTP header key for CopyObject API. + sseCopyCustomerKey = "X-Amz-Copy-Source-Server-Side-Encryption-Customer-Key" + // sseCopyCustomerKeyMD5 is the AWS SSE-C encryption key MD5 HTTP header key for CopyObject API. + sseCopyCustomerKeyMD5 = "X-Amz-Copy-Source-Server-Side-Encryption-Customer-Key-MD5" +) + +// PBKDF creates a SSE-C key from the provided password and salt. +// PBKDF is a password-based key derivation function +// which can be used to derive a high-entropy cryptographic +// key from a low-entropy password and a salt. +type PBKDF func(password, salt []byte) ServerSide + +// DefaultPBKDF is the default PBKDF. It uses Argon2id with the +// recommended parameters from the RFC draft (1 pass, 64 MB memory, 4 threads). +var DefaultPBKDF PBKDF = func(password, salt []byte) ServerSide { + sse := ssec{} + copy(sse[:], argon2.IDKey(password, salt, 1, 64*1024, 4, 32)) + return sse +} + +// Type is the server-side-encryption method. It represents one of +// the following encryption methods: +// - SSE-C: server-side-encryption with customer provided keys +// - KMS: server-side-encryption with managed keys +// - S3: server-side-encryption using S3 storage encryption +type Type string + +const ( + // SSEC represents server-side-encryption with customer provided keys + SSEC Type = "SSE-C" + // KMS represents server-side-encryption with managed keys + KMS Type = "KMS" + // S3 represents server-side-encryption using S3 storage encryption + S3 Type = "S3" +) + +// ServerSide is a form of S3 server-side-encryption. +type ServerSide interface { + // Type returns the server-side-encryption method. + Type() Type + + // Marshal adds encryption headers to the provided HTTP headers. + // It marks an HTTP request as server-side-encryption request + // and inserts the required data into the headers. + Marshal(h http.Header) +} + +// NewSSE returns a server-side-encryption using S3 storage encryption. +// Using SSE-S3 the server will encrypt the object with server-managed keys. +func NewSSE() ServerSide { return s3{} } + +// NewSSEKMS returns a new server-side-encryption using SSE-KMS and the provided Key Id and context. +func NewSSEKMS(keyID string, context interface{}) (ServerSide, error) { + if context == nil { + return kms{key: keyID, hasContext: false}, nil + } + serializedContext, err := json.Marshal(context) + if err != nil { + return nil, err + } + return kms{key: keyID, context: serializedContext, hasContext: true}, nil +} + +// NewSSEC returns a new server-side-encryption using SSE-C and the provided key. +// The key must be 32 bytes long. +func NewSSEC(key []byte) (ServerSide, error) { + if len(key) != 32 { + return nil, errors.New("encrypt: SSE-C key must be 256 bit long") + } + sse := ssec{} + copy(sse[:], key) + return sse, nil +} + +// SSE transforms a SSE-C copy encryption into a SSE-C encryption. +// It is the inverse of SSECopy(...). +// +// If the provided sse is no SSE-C copy encryption SSE returns +// sse unmodified. +func SSE(sse ServerSide) ServerSide { + if sse == nil || sse.Type() != SSEC { + return sse + } + if sse, ok := sse.(ssecCopy); ok { + return ssec(sse) + } + return sse +} + +// SSECopy transforms a SSE-C encryption into a SSE-C copy +// encryption. This is required for SSE-C key rotation or a SSE-C +// copy where the source and the destination should be encrypted. +// +// If the provided sse is no SSE-C encryption SSECopy returns +// sse unmodified. +func SSECopy(sse ServerSide) ServerSide { + if sse == nil || sse.Type() != SSEC { + return sse + } + if sse, ok := sse.(ssec); ok { + return ssecCopy(sse) + } + return sse +} + +type ssec [32]byte + +func (s ssec) Type() Type { return SSEC } + +func (s ssec) Marshal(h http.Header) { + keyMD5 := md5.Sum(s[:]) + h.Set(sseCustomerAlgorithm, "AES256") + h.Set(sseCustomerKey, base64.StdEncoding.EncodeToString(s[:])) + h.Set(sseCustomerKeyMD5, base64.StdEncoding.EncodeToString(keyMD5[:])) +} + +type ssecCopy [32]byte + +func (s ssecCopy) Type() Type { return SSEC } + +func (s ssecCopy) Marshal(h http.Header) { + keyMD5 := md5.Sum(s[:]) + h.Set(sseCopyCustomerAlgorithm, "AES256") + h.Set(sseCopyCustomerKey, base64.StdEncoding.EncodeToString(s[:])) + h.Set(sseCopyCustomerKeyMD5, base64.StdEncoding.EncodeToString(keyMD5[:])) +} + +type s3 struct{} + +func (s s3) Type() Type { return S3 } + +func (s s3) Marshal(h http.Header) { h.Set(sseGenericHeader, "AES256") } + +type kms struct { + key string + context []byte + hasContext bool +} + +func (s kms) Type() Type { return KMS } + +func (s kms) Marshal(h http.Header) { + h.Set(sseGenericHeader, "aws:kms") + h.Set(sseKmsKeyID, s.key) + if s.hasContext { + h.Set(sseEncryptionContext, base64.StdEncoding.EncodeToString(s.context)) + } +} diff --git a/vendor/github.com/minio/minio-go/pkg/s3signer/request-signature-streaming.go b/vendor/github.com/minio/minio-go/pkg/s3signer/request-signature-streaming.go new file mode 100644 index 0000000000000..156a6d63a61cf --- /dev/null +++ b/vendor/github.com/minio/minio-go/pkg/s3signer/request-signature-streaming.go @@ -0,0 +1,306 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package s3signer + +import ( + "bytes" + "encoding/hex" + "fmt" + "io" + "io/ioutil" + "net/http" + "strconv" + "strings" + "time" +) + +// Reference for constants used below - +// http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-streaming.html#example-signature-calculations-streaming +const ( + streamingSignAlgorithm = "STREAMING-AWS4-HMAC-SHA256-PAYLOAD" + streamingPayloadHdr = "AWS4-HMAC-SHA256-PAYLOAD" + emptySHA256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + payloadChunkSize = 64 * 1024 + chunkSigConstLen = 17 // ";chunk-signature=" + signatureStrLen = 64 // e.g. "f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2" + crlfLen = 2 // CRLF +) + +// Request headers to be ignored while calculating seed signature for +// a request. +var ignoredStreamingHeaders = map[string]bool{ + "Authorization": true, + "User-Agent": true, + "Content-Type": true, +} + +// getSignedChunkLength - calculates the length of chunk metadata +func getSignedChunkLength(chunkDataSize int64) int64 { + return int64(len(fmt.Sprintf("%x", chunkDataSize))) + + chunkSigConstLen + + signatureStrLen + + crlfLen + + chunkDataSize + + crlfLen +} + +// getStreamLength - calculates the length of the overall stream (data + metadata) +func getStreamLength(dataLen, chunkSize int64) int64 { + if dataLen <= 0 { + return 0 + } + + chunksCount := int64(dataLen / chunkSize) + remainingBytes := int64(dataLen % chunkSize) + streamLen := int64(0) + streamLen += chunksCount * getSignedChunkLength(chunkSize) + if remainingBytes > 0 { + streamLen += getSignedChunkLength(remainingBytes) + } + streamLen += getSignedChunkLength(0) + return streamLen +} + +// buildChunkStringToSign - returns the string to sign given chunk data +// and previous signature. +func buildChunkStringToSign(t time.Time, region, previousSig string, chunkData []byte) string { + stringToSignParts := []string{ + streamingPayloadHdr, + t.Format(iso8601DateFormat), + getScope(region, t), + previousSig, + emptySHA256, + hex.EncodeToString(sum256(chunkData)), + } + + return strings.Join(stringToSignParts, "\n") +} + +// prepareStreamingRequest - prepares a request with appropriate +// headers before computing the seed signature. +func prepareStreamingRequest(req *http.Request, sessionToken string, dataLen int64, timestamp time.Time) { + // Set x-amz-content-sha256 header. + req.Header.Set("X-Amz-Content-Sha256", streamingSignAlgorithm) + if sessionToken != "" { + req.Header.Set("X-Amz-Security-Token", sessionToken) + } + + req.Header.Set("X-Amz-Date", timestamp.Format(iso8601DateFormat)) + // Set content length with streaming signature for each chunk included. + req.ContentLength = getStreamLength(dataLen, int64(payloadChunkSize)) + req.Header.Set("x-amz-decoded-content-length", strconv.FormatInt(dataLen, 10)) +} + +// buildChunkHeader - returns the chunk header. +// e.g string(IntHexBase(chunk-size)) + ";chunk-signature=" + signature + \r\n + chunk-data + \r\n +func buildChunkHeader(chunkLen int64, signature string) []byte { + return []byte(strconv.FormatInt(chunkLen, 16) + ";chunk-signature=" + signature + "\r\n") +} + +// buildChunkSignature - returns chunk signature for a given chunk and previous signature. +func buildChunkSignature(chunkData []byte, reqTime time.Time, region, + previousSignature, secretAccessKey string) string { + + chunkStringToSign := buildChunkStringToSign(reqTime, region, + previousSignature, chunkData) + signingKey := getSigningKey(secretAccessKey, region, reqTime) + return getSignature(signingKey, chunkStringToSign) +} + +// getSeedSignature - returns the seed signature for a given request. +func (s *StreamingReader) setSeedSignature(req *http.Request) { + // Get canonical request + canonicalRequest := getCanonicalRequest(*req, ignoredStreamingHeaders) + + // Get string to sign from canonical request. + stringToSign := getStringToSignV4(s.reqTime, s.region, canonicalRequest) + + signingKey := getSigningKey(s.secretAccessKey, s.region, s.reqTime) + + // Calculate signature. + s.seedSignature = getSignature(signingKey, stringToSign) +} + +// StreamingReader implements chunked upload signature as a reader on +// top of req.Body's ReaderCloser chunk header;data;... repeat +type StreamingReader struct { + accessKeyID string + secretAccessKey string + sessionToken string + region string + prevSignature string + seedSignature string + contentLen int64 // Content-Length from req header + baseReadCloser io.ReadCloser // underlying io.Reader + bytesRead int64 // bytes read from underlying io.Reader + buf bytes.Buffer // holds signed chunk + chunkBuf []byte // holds raw data read from req Body + chunkBufLen int // no. of bytes read so far into chunkBuf + done bool // done reading the underlying reader to EOF + reqTime time.Time + chunkNum int + totalChunks int + lastChunkSize int +} + +// signChunk - signs a chunk read from s.baseReader of chunkLen size. +func (s *StreamingReader) signChunk(chunkLen int) { + // Compute chunk signature for next header + signature := buildChunkSignature(s.chunkBuf[:chunkLen], s.reqTime, + s.region, s.prevSignature, s.secretAccessKey) + + // For next chunk signature computation + s.prevSignature = signature + + // Write chunk header into streaming buffer + chunkHdr := buildChunkHeader(int64(chunkLen), signature) + s.buf.Write(chunkHdr) + + // Write chunk data into streaming buffer + s.buf.Write(s.chunkBuf[:chunkLen]) + + // Write the chunk trailer. + s.buf.Write([]byte("\r\n")) + + // Reset chunkBufLen for next chunk read. + s.chunkBufLen = 0 + s.chunkNum++ +} + +// setStreamingAuthHeader - builds and sets authorization header value +// for streaming signature. +func (s *StreamingReader) setStreamingAuthHeader(req *http.Request) { + credential := GetCredential(s.accessKeyID, s.region, s.reqTime) + authParts := []string{ + signV4Algorithm + " Credential=" + credential, + "SignedHeaders=" + getSignedHeaders(*req, ignoredStreamingHeaders), + "Signature=" + s.seedSignature, + } + + // Set authorization header. + auth := strings.Join(authParts, ",") + req.Header.Set("Authorization", auth) +} + +// StreamingSignV4 - provides chunked upload signatureV4 support by +// implementing io.Reader. +func StreamingSignV4(req *http.Request, accessKeyID, secretAccessKey, sessionToken, + region string, dataLen int64, reqTime time.Time) *http.Request { + + // Set headers needed for streaming signature. + prepareStreamingRequest(req, sessionToken, dataLen, reqTime) + + if req.Body == nil { + req.Body = ioutil.NopCloser(bytes.NewReader([]byte(""))) + } + + stReader := &StreamingReader{ + baseReadCloser: req.Body, + accessKeyID: accessKeyID, + secretAccessKey: secretAccessKey, + sessionToken: sessionToken, + region: region, + reqTime: reqTime, + chunkBuf: make([]byte, payloadChunkSize), + contentLen: dataLen, + chunkNum: 1, + totalChunks: int((dataLen+payloadChunkSize-1)/payloadChunkSize) + 1, + lastChunkSize: int(dataLen % payloadChunkSize), + } + + // Add the request headers required for chunk upload signing. + + // Compute the seed signature. + stReader.setSeedSignature(req) + + // Set the authorization header with the seed signature. + stReader.setStreamingAuthHeader(req) + + // Set seed signature as prevSignature for subsequent + // streaming signing process. + stReader.prevSignature = stReader.seedSignature + req.Body = stReader + + return req +} + +// Read - this method performs chunk upload signature providing a +// io.Reader interface. +func (s *StreamingReader) Read(buf []byte) (int, error) { + switch { + // After the last chunk is read from underlying reader, we + // never re-fill s.buf. + case s.done: + + // s.buf will be (re-)filled with next chunk when has lesser + // bytes than asked for. + case s.buf.Len() < len(buf): + s.chunkBufLen = 0 + for { + n1, err := s.baseReadCloser.Read(s.chunkBuf[s.chunkBufLen:]) + // Usually we validate `err` first, but in this case + // we are validating n > 0 for the following reasons. + // + // 1. n > 0, err is one of io.EOF, nil (near end of stream) + // A Reader returning a non-zero number of bytes at the end + // of the input stream may return either err == EOF or err == nil + // + // 2. n == 0, err is io.EOF (actual end of stream) + // + // Callers should always process the n > 0 bytes returned + // before considering the error err. + if n1 > 0 { + s.chunkBufLen += n1 + s.bytesRead += int64(n1) + + if s.chunkBufLen == payloadChunkSize || + (s.chunkNum == s.totalChunks-1 && + s.chunkBufLen == s.lastChunkSize) { + // Sign the chunk and write it to s.buf. + s.signChunk(s.chunkBufLen) + break + } + } + if err != nil { + if err == io.EOF { + // No more data left in baseReader - last chunk. + // Done reading the last chunk from baseReader. + s.done = true + + // bytes read from baseReader different than + // content length provided. + if s.bytesRead != s.contentLen { + return 0, io.ErrUnexpectedEOF + } + + // Sign the chunk and write it to s.buf. + s.signChunk(0) + break + } + return 0, err + } + + } + } + return s.buf.Read(buf) +} + +// Close - this method makes underlying io.ReadCloser's Close method available. +func (s *StreamingReader) Close() error { + return s.baseReadCloser.Close() +} diff --git a/vendor/github.com/minio/minio-go/pkg/s3signer/request-signature-v2.go b/vendor/github.com/minio/minio-go/pkg/s3signer/request-signature-v2.go new file mode 100644 index 0000000000000..b4070938e0433 --- /dev/null +++ b/vendor/github.com/minio/minio-go/pkg/s3signer/request-signature-v2.go @@ -0,0 +1,316 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2015-2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package s3signer + +import ( + "bytes" + "crypto/hmac" + "crypto/sha1" + "encoding/base64" + "fmt" + "net/http" + "net/url" + "sort" + "strconv" + "strings" + "time" + + "github.com/minio/minio-go/pkg/s3utils" +) + +// Signature and API related constants. +const ( + signV2Algorithm = "AWS" +) + +// Encode input URL path to URL encoded path. +func encodeURL2Path(req *http.Request, virtualHost bool) (path string) { + if virtualHost { + reqHost := getHostAddr(req) + dotPos := strings.Index(reqHost, ".") + if dotPos > -1 { + bucketName := reqHost[:dotPos] + path = "/" + bucketName + path += req.URL.Path + path = s3utils.EncodePath(path) + return + } + } + path = s3utils.EncodePath(req.URL.Path) + return +} + +// PreSignV2 - presign the request in following style. +// https://${S3_BUCKET}.s3.amazonaws.com/${S3_OBJECT}?AWSAccessKeyId=${S3_ACCESS_KEY}&Expires=${TIMESTAMP}&Signature=${SIGNATURE}. +func PreSignV2(req http.Request, accessKeyID, secretAccessKey string, expires int64, virtualHost bool) *http.Request { + // Presign is not needed for anonymous credentials. + if accessKeyID == "" || secretAccessKey == "" { + return &req + } + + d := time.Now().UTC() + // Find epoch expires when the request will expire. + epochExpires := d.Unix() + expires + + // Add expires header if not present. + if expiresStr := req.Header.Get("Expires"); expiresStr == "" { + req.Header.Set("Expires", strconv.FormatInt(epochExpires, 10)) + } + + // Get presigned string to sign. + stringToSign := preStringToSignV2(req, virtualHost) + hm := hmac.New(sha1.New, []byte(secretAccessKey)) + hm.Write([]byte(stringToSign)) + + // Calculate signature. + signature := base64.StdEncoding.EncodeToString(hm.Sum(nil)) + + query := req.URL.Query() + // Handle specially for Google Cloud Storage. + if strings.Contains(getHostAddr(&req), ".storage.googleapis.com") { + query.Set("GoogleAccessId", accessKeyID) + } else { + query.Set("AWSAccessKeyId", accessKeyID) + } + + // Fill in Expires for presigned query. + query.Set("Expires", strconv.FormatInt(epochExpires, 10)) + + // Encode query and save. + req.URL.RawQuery = s3utils.QueryEncode(query) + + // Save signature finally. + req.URL.RawQuery += "&Signature=" + s3utils.EncodePath(signature) + + // Return. + return &req +} + +// PostPresignSignatureV2 - presigned signature for PostPolicy +// request. +func PostPresignSignatureV2(policyBase64, secretAccessKey string) string { + hm := hmac.New(sha1.New, []byte(secretAccessKey)) + hm.Write([]byte(policyBase64)) + signature := base64.StdEncoding.EncodeToString(hm.Sum(nil)) + return signature +} + +// Authorization = "AWS" + " " + AWSAccessKeyId + ":" + Signature; +// Signature = Base64( HMAC-SHA1( YourSecretAccessKeyID, UTF-8-Encoding-Of( StringToSign ) ) ); +// +// StringToSign = HTTP-Verb + "\n" + +// Content-Md5 + "\n" + +// Content-Type + "\n" + +// Date + "\n" + +// CanonicalizedProtocolHeaders + +// CanonicalizedResource; +// +// CanonicalizedResource = [ "/" + Bucket ] + +// + +// [ subresource, if present. For example "?acl", "?location", "?logging", or "?torrent"]; +// +// CanonicalizedProtocolHeaders = + +// SignV2 sign the request before Do() (AWS Signature Version 2). +func SignV2(req http.Request, accessKeyID, secretAccessKey string, virtualHost bool) *http.Request { + // Signature calculation is not needed for anonymous credentials. + if accessKeyID == "" || secretAccessKey == "" { + return &req + } + + // Initial time. + d := time.Now().UTC() + + // Add date if not present. + if date := req.Header.Get("Date"); date == "" { + req.Header.Set("Date", d.Format(http.TimeFormat)) + } + + // Calculate HMAC for secretAccessKey. + stringToSign := stringToSignV2(req, virtualHost) + hm := hmac.New(sha1.New, []byte(secretAccessKey)) + hm.Write([]byte(stringToSign)) + + // Prepare auth header. + authHeader := new(bytes.Buffer) + authHeader.WriteString(fmt.Sprintf("%s %s:", signV2Algorithm, accessKeyID)) + encoder := base64.NewEncoder(base64.StdEncoding, authHeader) + encoder.Write(hm.Sum(nil)) + encoder.Close() + + // Set Authorization header. + req.Header.Set("Authorization", authHeader.String()) + + return &req +} + +// From the Amazon docs: +// +// StringToSign = HTTP-Verb + "\n" + +// Content-Md5 + "\n" + +// Content-Type + "\n" + +// Expires + "\n" + +// CanonicalizedProtocolHeaders + +// CanonicalizedResource; +func preStringToSignV2(req http.Request, virtualHost bool) string { + buf := new(bytes.Buffer) + // Write standard headers. + writePreSignV2Headers(buf, req) + // Write canonicalized protocol headers if any. + writeCanonicalizedHeaders(buf, req) + // Write canonicalized Query resources if any. + writeCanonicalizedResource(buf, req, virtualHost) + return buf.String() +} + +// writePreSignV2Headers - write preSign v2 required headers. +func writePreSignV2Headers(buf *bytes.Buffer, req http.Request) { + buf.WriteString(req.Method + "\n") + buf.WriteString(req.Header.Get("Content-Md5") + "\n") + buf.WriteString(req.Header.Get("Content-Type") + "\n") + buf.WriteString(req.Header.Get("Expires") + "\n") +} + +// From the Amazon docs: +// +// StringToSign = HTTP-Verb + "\n" + +// Content-Md5 + "\n" + +// Content-Type + "\n" + +// Date + "\n" + +// CanonicalizedProtocolHeaders + +// CanonicalizedResource; +func stringToSignV2(req http.Request, virtualHost bool) string { + buf := new(bytes.Buffer) + // Write standard headers. + writeSignV2Headers(buf, req) + // Write canonicalized protocol headers if any. + writeCanonicalizedHeaders(buf, req) + // Write canonicalized Query resources if any. + writeCanonicalizedResource(buf, req, virtualHost) + return buf.String() +} + +// writeSignV2Headers - write signV2 required headers. +func writeSignV2Headers(buf *bytes.Buffer, req http.Request) { + buf.WriteString(req.Method + "\n") + buf.WriteString(req.Header.Get("Content-Md5") + "\n") + buf.WriteString(req.Header.Get("Content-Type") + "\n") + buf.WriteString(req.Header.Get("Date") + "\n") +} + +// writeCanonicalizedHeaders - write canonicalized headers. +func writeCanonicalizedHeaders(buf *bytes.Buffer, req http.Request) { + var protoHeaders []string + vals := make(map[string][]string) + for k, vv := range req.Header { + // All the AMZ headers should be lowercase + lk := strings.ToLower(k) + if strings.HasPrefix(lk, "x-amz") { + protoHeaders = append(protoHeaders, lk) + vals[lk] = vv + } + } + sort.Strings(protoHeaders) + for _, k := range protoHeaders { + buf.WriteString(k) + buf.WriteByte(':') + for idx, v := range vals[k] { + if idx > 0 { + buf.WriteByte(',') + } + if strings.Contains(v, "\n") { + // TODO: "Unfold" long headers that + // span multiple lines (as allowed by + // RFC 2616, section 4.2) by replacing + // the folding white-space (including + // new-line) by a single space. + buf.WriteString(v) + } else { + buf.WriteString(v) + } + } + buf.WriteByte('\n') + } +} + +// AWS S3 Signature V2 calculation rule is give here: +// http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html#RESTAuthenticationStringToSign + +// Whitelist resource list that will be used in query string for signature-V2 calculation. +// The list should be alphabetically sorted +var resourceList = []string{ + "acl", + "delete", + "lifecycle", + "location", + "logging", + "notification", + "partNumber", + "policy", + "requestPayment", + "response-cache-control", + "response-content-disposition", + "response-content-encoding", + "response-content-language", + "response-content-type", + "response-expires", + "torrent", + "uploadId", + "uploads", + "versionId", + "versioning", + "versions", + "website", +} + +// From the Amazon docs: +// +// CanonicalizedResource = [ "/" + Bucket ] + +// + +// [ sub-resource, if present. For example "?acl", "?location", "?logging", or "?torrent"]; +func writeCanonicalizedResource(buf *bytes.Buffer, req http.Request, virtualHost bool) { + // Save request URL. + requestURL := req.URL + // Get encoded URL path. + buf.WriteString(encodeURL2Path(&req, virtualHost)) + if requestURL.RawQuery != "" { + var n int + vals, _ := url.ParseQuery(requestURL.RawQuery) + // Verify if any sub resource queries are present, if yes + // canonicallize them. + for _, resource := range resourceList { + if vv, ok := vals[resource]; ok && len(vv) > 0 { + n++ + // First element + switch n { + case 1: + buf.WriteByte('?') + // The rest + default: + buf.WriteByte('&') + } + buf.WriteString(resource) + // Request parameters + if len(vv[0]) > 0 { + buf.WriteByte('=') + buf.WriteString(vv[0]) + } + } + } + } +} diff --git a/vendor/github.com/minio/minio-go/pkg/s3signer/request-signature-v4.go b/vendor/github.com/minio/minio-go/pkg/s3signer/request-signature-v4.go new file mode 100644 index 0000000000000..daf02fedf8280 --- /dev/null +++ b/vendor/github.com/minio/minio-go/pkg/s3signer/request-signature-v4.go @@ -0,0 +1,315 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2015-2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package s3signer + +import ( + "bytes" + "encoding/hex" + "net/http" + "sort" + "strconv" + "strings" + "time" + + "github.com/minio/minio-go/pkg/s3utils" +) + +// Signature and API related constants. +const ( + signV4Algorithm = "AWS4-HMAC-SHA256" + iso8601DateFormat = "20060102T150405Z" + yyyymmdd = "20060102" +) + +/// +/// Excerpts from @lsegal - +/// https://github.com/aws/aws-sdk-js/issues/659#issuecomment-120477258. +/// +/// User-Agent: +/// +/// This is ignored from signing because signing this causes +/// problems with generating pre-signed URLs (that are executed +/// by other agents) or when customers pass requests through +/// proxies, which may modify the user-agent. +/// +/// Content-Length: +/// +/// This is ignored from signing because generating a pre-signed +/// URL should not provide a content-length constraint, +/// specifically when vending a S3 pre-signed PUT URL. The +/// corollary to this is that when sending regular requests +/// (non-pre-signed), the signature contains a checksum of the +/// body, which implicitly validates the payload length (since +/// changing the number of bytes would change the checksum) +/// and therefore this header is not valuable in the signature. +/// +/// Content-Type: +/// +/// Signing this header causes quite a number of problems in +/// browser environments, where browsers like to modify and +/// normalize the content-type header in different ways. There is +/// more information on this in https://goo.gl/2E9gyy. Avoiding +/// this field simplifies logic and reduces the possibility of +/// future bugs. +/// +/// Authorization: +/// +/// Is skipped for obvious reasons +/// +var v4IgnoredHeaders = map[string]bool{ + "Authorization": true, + "Content-Type": true, + "Content-Length": true, + "User-Agent": true, +} + +// getSigningKey hmac seed to calculate final signature. +func getSigningKey(secret, loc string, t time.Time) []byte { + date := sumHMAC([]byte("AWS4"+secret), []byte(t.Format(yyyymmdd))) + location := sumHMAC(date, []byte(loc)) + service := sumHMAC(location, []byte("s3")) + signingKey := sumHMAC(service, []byte("aws4_request")) + return signingKey +} + +// getSignature final signature in hexadecimal form. +func getSignature(signingKey []byte, stringToSign string) string { + return hex.EncodeToString(sumHMAC(signingKey, []byte(stringToSign))) +} + +// getScope generate a string of a specific date, an AWS region, and a +// service. +func getScope(location string, t time.Time) string { + scope := strings.Join([]string{ + t.Format(yyyymmdd), + location, + "s3", + "aws4_request", + }, "/") + return scope +} + +// GetCredential generate a credential string. +func GetCredential(accessKeyID, location string, t time.Time) string { + scope := getScope(location, t) + return accessKeyID + "/" + scope +} + +// getHashedPayload get the hexadecimal value of the SHA256 hash of +// the request payload. +func getHashedPayload(req http.Request) string { + hashedPayload := req.Header.Get("X-Amz-Content-Sha256") + if hashedPayload == "" { + // Presign does not have a payload, use S3 recommended value. + hashedPayload = unsignedPayload + } + return hashedPayload +} + +// getCanonicalHeaders generate a list of request headers for +// signature. +func getCanonicalHeaders(req http.Request, ignoredHeaders map[string]bool) string { + var headers []string + vals := make(map[string][]string) + for k, vv := range req.Header { + if _, ok := ignoredHeaders[http.CanonicalHeaderKey(k)]; ok { + continue // ignored header + } + headers = append(headers, strings.ToLower(k)) + vals[strings.ToLower(k)] = vv + } + headers = append(headers, "host") + sort.Strings(headers) + + var buf bytes.Buffer + // Save all the headers in canonical form
: newline + // separated for each header. + for _, k := range headers { + buf.WriteString(k) + buf.WriteByte(':') + switch { + case k == "host": + buf.WriteString(getHostAddr(&req)) + fallthrough + default: + for idx, v := range vals[k] { + if idx > 0 { + buf.WriteByte(',') + } + buf.WriteString(v) + } + buf.WriteByte('\n') + } + } + return buf.String() +} + +// getSignedHeaders generate all signed request headers. +// i.e lexically sorted, semicolon-separated list of lowercase +// request header names. +func getSignedHeaders(req http.Request, ignoredHeaders map[string]bool) string { + var headers []string + for k := range req.Header { + if _, ok := ignoredHeaders[http.CanonicalHeaderKey(k)]; ok { + continue // Ignored header found continue. + } + headers = append(headers, strings.ToLower(k)) + } + headers = append(headers, "host") + sort.Strings(headers) + return strings.Join(headers, ";") +} + +// getCanonicalRequest generate a canonical request of style. +// +// canonicalRequest = +// \n +// \n +// \n +// \n +// \n +// +func getCanonicalRequest(req http.Request, ignoredHeaders map[string]bool) string { + req.URL.RawQuery = strings.Replace(req.URL.Query().Encode(), "+", "%20", -1) + canonicalRequest := strings.Join([]string{ + req.Method, + s3utils.EncodePath(req.URL.Path), + req.URL.RawQuery, + getCanonicalHeaders(req, ignoredHeaders), + getSignedHeaders(req, ignoredHeaders), + getHashedPayload(req), + }, "\n") + return canonicalRequest +} + +// getStringToSign a string based on selected query values. +func getStringToSignV4(t time.Time, location, canonicalRequest string) string { + stringToSign := signV4Algorithm + "\n" + t.Format(iso8601DateFormat) + "\n" + stringToSign = stringToSign + getScope(location, t) + "\n" + stringToSign = stringToSign + hex.EncodeToString(sum256([]byte(canonicalRequest))) + return stringToSign +} + +// PreSignV4 presign the request, in accordance with +// http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html. +func PreSignV4(req http.Request, accessKeyID, secretAccessKey, sessionToken, location string, expires int64) *http.Request { + // Presign is not needed for anonymous credentials. + if accessKeyID == "" || secretAccessKey == "" { + return &req + } + + // Initial time. + t := time.Now().UTC() + + // Get credential string. + credential := GetCredential(accessKeyID, location, t) + + // Get all signed headers. + signedHeaders := getSignedHeaders(req, v4IgnoredHeaders) + + // Set URL query. + query := req.URL.Query() + query.Set("X-Amz-Algorithm", signV4Algorithm) + query.Set("X-Amz-Date", t.Format(iso8601DateFormat)) + query.Set("X-Amz-Expires", strconv.FormatInt(expires, 10)) + query.Set("X-Amz-SignedHeaders", signedHeaders) + query.Set("X-Amz-Credential", credential) + // Set session token if available. + if sessionToken != "" { + query.Set("X-Amz-Security-Token", sessionToken) + } + req.URL.RawQuery = query.Encode() + + // Get canonical request. + canonicalRequest := getCanonicalRequest(req, v4IgnoredHeaders) + + // Get string to sign from canonical request. + stringToSign := getStringToSignV4(t, location, canonicalRequest) + + // Gext hmac signing key. + signingKey := getSigningKey(secretAccessKey, location, t) + + // Calculate signature. + signature := getSignature(signingKey, stringToSign) + + // Add signature header to RawQuery. + req.URL.RawQuery += "&X-Amz-Signature=" + signature + + return &req +} + +// PostPresignSignatureV4 - presigned signature for PostPolicy +// requests. +func PostPresignSignatureV4(policyBase64 string, t time.Time, secretAccessKey, location string) string { + // Get signining key. + signingkey := getSigningKey(secretAccessKey, location, t) + // Calculate signature. + signature := getSignature(signingkey, policyBase64) + return signature +} + +// SignV4 sign the request before Do(), in accordance with +// http://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html. +func SignV4(req http.Request, accessKeyID, secretAccessKey, sessionToken, location string) *http.Request { + // Signature calculation is not needed for anonymous credentials. + if accessKeyID == "" || secretAccessKey == "" { + return &req + } + + // Initial time. + t := time.Now().UTC() + + // Set x-amz-date. + req.Header.Set("X-Amz-Date", t.Format(iso8601DateFormat)) + + // Set session token if available. + if sessionToken != "" { + req.Header.Set("X-Amz-Security-Token", sessionToken) + } + + // Get canonical request. + canonicalRequest := getCanonicalRequest(req, v4IgnoredHeaders) + + // Get string to sign from canonical request. + stringToSign := getStringToSignV4(t, location, canonicalRequest) + + // Get hmac signing key. + signingKey := getSigningKey(secretAccessKey, location, t) + + // Get credential string. + credential := GetCredential(accessKeyID, location, t) + + // Get all signed headers. + signedHeaders := getSignedHeaders(req, v4IgnoredHeaders) + + // Calculate signature. + signature := getSignature(signingKey, stringToSign) + + // If regular request, construct the final authorization header. + parts := []string{ + signV4Algorithm + " Credential=" + credential, + "SignedHeaders=" + signedHeaders, + "Signature=" + signature, + } + + // Set authorization header. + auth := strings.Join(parts, ", ") + req.Header.Set("Authorization", auth) + + return &req +} diff --git a/vendor/github.com/minio/minio-go/pkg/s3signer/utils.go b/vendor/github.com/minio/minio-go/pkg/s3signer/utils.go new file mode 100644 index 0000000000000..33b1752083f8b --- /dev/null +++ b/vendor/github.com/minio/minio-go/pkg/s3signer/utils.go @@ -0,0 +1,49 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2015-2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package s3signer + +import ( + "crypto/hmac" + "crypto/sha256" + "net/http" +) + +// unsignedPayload - value to be set to X-Amz-Content-Sha256 header when +const unsignedPayload = "UNSIGNED-PAYLOAD" + +// sum256 calculate sha256 sum for an input byte array. +func sum256(data []byte) []byte { + hash := sha256.New() + hash.Write(data) + return hash.Sum(nil) +} + +// sumHMAC calculate hmac between two input byte array. +func sumHMAC(key []byte, data []byte) []byte { + hash := hmac.New(sha256.New, key) + hash.Write(data) + return hash.Sum(nil) +} + +// getHostAddr returns host header if available, otherwise returns host from URL +func getHostAddr(req *http.Request) string { + if req.Host != "" { + return req.Host + } + return req.URL.Host +} diff --git a/vendor/github.com/minio/minio-go/pkg/s3utils/utils.go b/vendor/github.com/minio/minio-go/pkg/s3utils/utils.go new file mode 100644 index 0000000000000..adceb7f2abc26 --- /dev/null +++ b/vendor/github.com/minio/minio-go/pkg/s3utils/utils.go @@ -0,0 +1,331 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2015-2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package s3utils + +import ( + "bytes" + "encoding/hex" + "errors" + "net" + "net/url" + "regexp" + "sort" + "strings" + "unicode/utf8" +) + +// Sentinel URL is the default url value which is invalid. +var sentinelURL = url.URL{} + +// IsValidDomain validates if input string is a valid domain name. +func IsValidDomain(host string) bool { + // See RFC 1035, RFC 3696. + host = strings.TrimSpace(host) + if len(host) == 0 || len(host) > 255 { + return false + } + // host cannot start or end with "-" + if host[len(host)-1:] == "-" || host[:1] == "-" { + return false + } + // host cannot start or end with "_" + if host[len(host)-1:] == "_" || host[:1] == "_" { + return false + } + // host cannot start or end with a "." + if host[len(host)-1:] == "." || host[:1] == "." { + return false + } + // All non alphanumeric characters are invalid. + if strings.ContainsAny(host, "`~!@#$%^&*()+={}[]|\\\"';:> 1 { + return parts[1] + } + parts = amazonS3HostHyphen.FindStringSubmatch(endpointURL.Host) + if len(parts) > 1 { + return parts[1] + } + parts = amazonS3ChinaHost.FindStringSubmatch(endpointURL.Host) + if len(parts) > 1 { + return parts[1] + } + parts = amazonS3HostDot.FindStringSubmatch(endpointURL.Host) + if len(parts) > 1 { + return parts[1] + } + return "" +} + +// IsAmazonEndpoint - Match if it is exactly Amazon S3 endpoint. +func IsAmazonEndpoint(endpointURL url.URL) bool { + if endpointURL.Host == "s3-external-1.amazonaws.com" || endpointURL.Host == "s3.amazonaws.com" { + return true + } + return GetRegionFromURL(endpointURL) != "" +} + +// IsAmazonGovCloudEndpoint - Match if it is exactly Amazon S3 GovCloud endpoint. +func IsAmazonGovCloudEndpoint(endpointURL url.URL) bool { + if endpointURL == sentinelURL { + return false + } + return (endpointURL.Host == "s3-us-gov-west-1.amazonaws.com" || + IsAmazonFIPSGovCloudEndpoint(endpointURL)) +} + +// IsAmazonFIPSGovCloudEndpoint - Match if it is exactly Amazon S3 FIPS GovCloud endpoint. +// See https://aws.amazon.com/compliance/fips. +func IsAmazonFIPSGovCloudEndpoint(endpointURL url.URL) bool { + if endpointURL == sentinelURL { + return false + } + return endpointURL.Host == "s3-fips-us-gov-west-1.amazonaws.com" || + endpointURL.Host == "s3-fips.dualstack.us-gov-west-1.amazonaws.com" +} + +// IsAmazonFIPSUSEastWestEndpoint - Match if it is exactly Amazon S3 FIPS US East/West endpoint. +// See https://aws.amazon.com/compliance/fips. +func IsAmazonFIPSUSEastWestEndpoint(endpointURL url.URL) bool { + if endpointURL == sentinelURL { + return false + } + switch endpointURL.Host { + case "s3-fips.us-east-2.amazonaws.com": + case "s3-fips.dualstack.us-west-1.amazonaws.com": + case "s3-fips.dualstack.us-west-2.amazonaws.com": + case "s3-fips.dualstack.us-east-2.amazonaws.com": + case "s3-fips.dualstack.us-east-1.amazonaws.com": + case "s3-fips.us-west-1.amazonaws.com": + case "s3-fips.us-west-2.amazonaws.com": + case "s3-fips.us-east-1.amazonaws.com": + default: + return false + } + return true +} + +// IsAmazonFIPSEndpoint - Match if it is exactly Amazon S3 FIPS endpoint. +// See https://aws.amazon.com/compliance/fips. +func IsAmazonFIPSEndpoint(endpointURL url.URL) bool { + return IsAmazonFIPSUSEastWestEndpoint(endpointURL) || IsAmazonFIPSGovCloudEndpoint(endpointURL) +} + +// IsGoogleEndpoint - Match if it is exactly Google cloud storage endpoint. +func IsGoogleEndpoint(endpointURL url.URL) bool { + if endpointURL == sentinelURL { + return false + } + return endpointURL.Host == "storage.googleapis.com" +} + +// Expects ascii encoded strings - from output of urlEncodePath +func percentEncodeSlash(s string) string { + return strings.Replace(s, "/", "%2F", -1) +} + +// QueryEncode - encodes query values in their URL encoded form. In +// addition to the percent encoding performed by urlEncodePath() used +// here, it also percent encodes '/' (forward slash) +func QueryEncode(v url.Values) string { + if v == nil { + return "" + } + var buf bytes.Buffer + keys := make([]string, 0, len(v)) + for k := range v { + keys = append(keys, k) + } + sort.Strings(keys) + for _, k := range keys { + vs := v[k] + prefix := percentEncodeSlash(EncodePath(k)) + "=" + for _, v := range vs { + if buf.Len() > 0 { + buf.WriteByte('&') + } + buf.WriteString(prefix) + buf.WriteString(percentEncodeSlash(EncodePath(v))) + } + } + return buf.String() +} + +// if object matches reserved string, no need to encode them +var reservedObjectNames = regexp.MustCompile("^[a-zA-Z0-9-_.~/]+$") + +// EncodePath encode the strings from UTF-8 byte representations to HTML hex escape sequences +// +// This is necessary since regular url.Parse() and url.Encode() functions do not support UTF-8 +// non english characters cannot be parsed due to the nature in which url.Encode() is written +// +// This function on the other hand is a direct replacement for url.Encode() technique to support +// pretty much every UTF-8 character. +func EncodePath(pathName string) string { + if reservedObjectNames.MatchString(pathName) { + return pathName + } + var encodedPathname string + for _, s := range pathName { + if 'A' <= s && s <= 'Z' || 'a' <= s && s <= 'z' || '0' <= s && s <= '9' { // §2.3 Unreserved characters (mark) + encodedPathname = encodedPathname + string(s) + continue + } + switch s { + case '-', '_', '.', '~', '/': // §2.3 Unreserved characters (mark) + encodedPathname = encodedPathname + string(s) + continue + default: + len := utf8.RuneLen(s) + if len < 0 { + // if utf8 cannot convert return the same string as is + return pathName + } + u := make([]byte, len) + utf8.EncodeRune(u, s) + for _, r := range u { + hex := hex.EncodeToString([]byte{r}) + encodedPathname = encodedPathname + "%" + strings.ToUpper(hex) + } + } + } + return encodedPathname +} + +// We support '.' with bucket names but we fallback to using path +// style requests instead for such buckets. +var ( + validBucketName = regexp.MustCompile(`^[A-Za-z0-9][A-Za-z0-9\.\-\_\:]{1,61}[A-Za-z0-9]$`) + validBucketNameStrict = regexp.MustCompile(`^[a-z0-9][a-z0-9\.\-]{1,61}[a-z0-9]$`) + ipAddress = regexp.MustCompile(`^(\d+\.){3}\d+$`) +) + +// Common checker for both stricter and basic validation. +func checkBucketNameCommon(bucketName string, strict bool) (err error) { + if strings.TrimSpace(bucketName) == "" { + return errors.New("Bucket name cannot be empty") + } + if len(bucketName) < 3 { + return errors.New("Bucket name cannot be smaller than 3 characters") + } + if len(bucketName) > 63 { + return errors.New("Bucket name cannot be greater than 63 characters") + } + if ipAddress.MatchString(bucketName) { + return errors.New("Bucket name cannot be an ip address") + } + if strings.Contains(bucketName, "..") { + return errors.New("Bucket name contains invalid characters") + } + if strict { + if !validBucketNameStrict.MatchString(bucketName) { + err = errors.New("Bucket name contains invalid characters") + } + return err + } + if !validBucketName.MatchString(bucketName) { + err = errors.New("Bucket name contains invalid characters") + } + return err +} + +// CheckValidBucketName - checks if we have a valid input bucket name. +func CheckValidBucketName(bucketName string) (err error) { + return checkBucketNameCommon(bucketName, false) +} + +// CheckValidBucketNameStrict - checks if we have a valid input bucket name. +// This is a stricter version. +// - http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html +func CheckValidBucketNameStrict(bucketName string) (err error) { + return checkBucketNameCommon(bucketName, true) +} + +// CheckValidObjectNamePrefix - checks if we have a valid input object name prefix. +// - http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html +func CheckValidObjectNamePrefix(objectName string) error { + if len(objectName) > 1024 { + return errors.New("Object name cannot be greater than 1024 characters") + } + if !utf8.ValidString(objectName) { + return errors.New("Object name with non UTF-8 strings are not supported") + } + return nil +} + +// CheckValidObjectName - checks if we have a valid input object name. +// - http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html +func CheckValidObjectName(objectName string) error { + if strings.TrimSpace(objectName) == "" { + return errors.New("Object name cannot be empty") + } + return CheckValidObjectNamePrefix(objectName) +} diff --git a/vendor/github.com/minio/minio-go/pkg/set/stringset.go b/vendor/github.com/minio/minio-go/pkg/set/stringset.go new file mode 100644 index 0000000000000..efd02629beef4 --- /dev/null +++ b/vendor/github.com/minio/minio-go/pkg/set/stringset.go @@ -0,0 +1,197 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2015-2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package set + +import ( + "encoding/json" + "fmt" + "sort" +) + +// StringSet - uses map as set of strings. +type StringSet map[string]struct{} + +// ToSlice - returns StringSet as string slice. +func (set StringSet) ToSlice() []string { + keys := make([]string, 0, len(set)) + for k := range set { + keys = append(keys, k) + } + sort.Strings(keys) + return keys +} + +// IsEmpty - returns whether the set is empty or not. +func (set StringSet) IsEmpty() bool { + return len(set) == 0 +} + +// Add - adds string to the set. +func (set StringSet) Add(s string) { + set[s] = struct{}{} +} + +// Remove - removes string in the set. It does nothing if string does not exist in the set. +func (set StringSet) Remove(s string) { + delete(set, s) +} + +// Contains - checks if string is in the set. +func (set StringSet) Contains(s string) bool { + _, ok := set[s] + return ok +} + +// FuncMatch - returns new set containing each value who passes match function. +// A 'matchFn' should accept element in a set as first argument and +// 'matchString' as second argument. The function can do any logic to +// compare both the arguments and should return true to accept element in +// a set to include in output set else the element is ignored. +func (set StringSet) FuncMatch(matchFn func(string, string) bool, matchString string) StringSet { + nset := NewStringSet() + for k := range set { + if matchFn(k, matchString) { + nset.Add(k) + } + } + return nset +} + +// ApplyFunc - returns new set containing each value processed by 'applyFn'. +// A 'applyFn' should accept element in a set as a argument and return +// a processed string. The function can do any logic to return a processed +// string. +func (set StringSet) ApplyFunc(applyFn func(string) string) StringSet { + nset := NewStringSet() + for k := range set { + nset.Add(applyFn(k)) + } + return nset +} + +// Equals - checks whether given set is equal to current set or not. +func (set StringSet) Equals(sset StringSet) bool { + // If length of set is not equal to length of given set, the + // set is not equal to given set. + if len(set) != len(sset) { + return false + } + + // As both sets are equal in length, check each elements are equal. + for k := range set { + if _, ok := sset[k]; !ok { + return false + } + } + + return true +} + +// Intersection - returns the intersection with given set as new set. +func (set StringSet) Intersection(sset StringSet) StringSet { + nset := NewStringSet() + for k := range set { + if _, ok := sset[k]; ok { + nset.Add(k) + } + } + + return nset +} + +// Difference - returns the difference with given set as new set. +func (set StringSet) Difference(sset StringSet) StringSet { + nset := NewStringSet() + for k := range set { + if _, ok := sset[k]; !ok { + nset.Add(k) + } + } + + return nset +} + +// Union - returns the union with given set as new set. +func (set StringSet) Union(sset StringSet) StringSet { + nset := NewStringSet() + for k := range set { + nset.Add(k) + } + + for k := range sset { + nset.Add(k) + } + + return nset +} + +// MarshalJSON - converts to JSON data. +func (set StringSet) MarshalJSON() ([]byte, error) { + return json.Marshal(set.ToSlice()) +} + +// UnmarshalJSON - parses JSON data and creates new set with it. +// If 'data' contains JSON string array, the set contains each string. +// If 'data' contains JSON string, the set contains the string as one element. +// If 'data' contains Other JSON types, JSON parse error is returned. +func (set *StringSet) UnmarshalJSON(data []byte) error { + sl := []string{} + var err error + if err = json.Unmarshal(data, &sl); err == nil { + *set = make(StringSet) + for _, s := range sl { + set.Add(s) + } + } else { + var s string + if err = json.Unmarshal(data, &s); err == nil { + *set = make(StringSet) + set.Add(s) + } + } + + return err +} + +// String - returns printable string of the set. +func (set StringSet) String() string { + return fmt.Sprintf("%s", set.ToSlice()) +} + +// NewStringSet - creates new string set. +func NewStringSet() StringSet { + return make(StringSet) +} + +// CreateStringSet - creates new string set with given string values. +func CreateStringSet(sl ...string) StringSet { + set := make(StringSet) + for _, k := range sl { + set.Add(k) + } + return set +} + +// CopyStringSet - returns copy of given set. +func CopyStringSet(set StringSet) StringSet { + nset := NewStringSet() + for k, v := range set { + nset[k] = v + } + return nset +} diff --git a/vendor/github.com/minio/minio-go/post-policy.go b/vendor/github.com/minio/minio-go/post-policy.go new file mode 100644 index 0000000000000..c285fdefdf2ec --- /dev/null +++ b/vendor/github.com/minio/minio-go/post-policy.go @@ -0,0 +1,270 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2015-2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package minio + +import ( + "encoding/base64" + "fmt" + "strings" + "time" +) + +// expirationDateFormat date format for expiration key in json policy. +const expirationDateFormat = "2006-01-02T15:04:05.999Z" + +// policyCondition explanation: +// http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-HTTPPOSTConstructPolicy.html +// +// Example: +// +// policyCondition { +// matchType: "$eq", +// key: "$Content-Type", +// value: "image/png", +// } +// +type policyCondition struct { + matchType string + condition string + value string +} + +// PostPolicy - Provides strict static type conversion and validation +// for Amazon S3's POST policy JSON string. +type PostPolicy struct { + // Expiration date and time of the POST policy. + expiration time.Time + // Collection of different policy conditions. + conditions []policyCondition + // ContentLengthRange minimum and maximum allowable size for the + // uploaded content. + contentLengthRange struct { + min int64 + max int64 + } + + // Post form data. + formData map[string]string +} + +// NewPostPolicy - Instantiate new post policy. +func NewPostPolicy() *PostPolicy { + p := &PostPolicy{} + p.conditions = make([]policyCondition, 0) + p.formData = make(map[string]string) + return p +} + +// SetExpires - Sets expiration time for the new policy. +func (p *PostPolicy) SetExpires(t time.Time) error { + if t.IsZero() { + return ErrInvalidArgument("No expiry time set.") + } + p.expiration = t + return nil +} + +// SetKey - Sets an object name for the policy based upload. +func (p *PostPolicy) SetKey(key string) error { + if strings.TrimSpace(key) == "" || key == "" { + return ErrInvalidArgument("Object name is empty.") + } + policyCond := policyCondition{ + matchType: "eq", + condition: "$key", + value: key, + } + if err := p.addNewPolicy(policyCond); err != nil { + return err + } + p.formData["key"] = key + return nil +} + +// SetKeyStartsWith - Sets an object name that an policy based upload +// can start with. +func (p *PostPolicy) SetKeyStartsWith(keyStartsWith string) error { + if strings.TrimSpace(keyStartsWith) == "" || keyStartsWith == "" { + return ErrInvalidArgument("Object prefix is empty.") + } + policyCond := policyCondition{ + matchType: "starts-with", + condition: "$key", + value: keyStartsWith, + } + if err := p.addNewPolicy(policyCond); err != nil { + return err + } + p.formData["key"] = keyStartsWith + return nil +} + +// SetBucket - Sets bucket at which objects will be uploaded to. +func (p *PostPolicy) SetBucket(bucketName string) error { + if strings.TrimSpace(bucketName) == "" || bucketName == "" { + return ErrInvalidArgument("Bucket name is empty.") + } + policyCond := policyCondition{ + matchType: "eq", + condition: "$bucket", + value: bucketName, + } + if err := p.addNewPolicy(policyCond); err != nil { + return err + } + p.formData["bucket"] = bucketName + return nil +} + +// SetContentType - Sets content-type of the object for this policy +// based upload. +func (p *PostPolicy) SetContentType(contentType string) error { + if strings.TrimSpace(contentType) == "" || contentType == "" { + return ErrInvalidArgument("No content type specified.") + } + policyCond := policyCondition{ + matchType: "eq", + condition: "$Content-Type", + value: contentType, + } + if err := p.addNewPolicy(policyCond); err != nil { + return err + } + p.formData["Content-Type"] = contentType + return nil +} + +// SetContentLengthRange - Set new min and max content length +// condition for all incoming uploads. +func (p *PostPolicy) SetContentLengthRange(min, max int64) error { + if min > max { + return ErrInvalidArgument("Minimum limit is larger than maximum limit.") + } + if min < 0 { + return ErrInvalidArgument("Minimum limit cannot be negative.") + } + if max < 0 { + return ErrInvalidArgument("Maximum limit cannot be negative.") + } + p.contentLengthRange.min = min + p.contentLengthRange.max = max + return nil +} + +// SetSuccessStatusAction - Sets the status success code of the object for this policy +// based upload. +func (p *PostPolicy) SetSuccessStatusAction(status string) error { + if strings.TrimSpace(status) == "" || status == "" { + return ErrInvalidArgument("Status is empty") + } + policyCond := policyCondition{ + matchType: "eq", + condition: "$success_action_status", + value: status, + } + if err := p.addNewPolicy(policyCond); err != nil { + return err + } + p.formData["success_action_status"] = status + return nil +} + +// SetUserMetadata - Set user metadata as a key/value couple. +// Can be retrieved through a HEAD request or an event. +func (p *PostPolicy) SetUserMetadata(key string, value string) error { + if strings.TrimSpace(key) == "" || key == "" { + return ErrInvalidArgument("Key is empty") + } + if strings.TrimSpace(value) == "" || value == "" { + return ErrInvalidArgument("Value is empty") + } + headerName := fmt.Sprintf("x-amz-meta-%s", key) + policyCond := policyCondition{ + matchType: "eq", + condition: fmt.Sprintf("$%s", headerName), + value: value, + } + if err := p.addNewPolicy(policyCond); err != nil { + return err + } + p.formData[headerName] = value + return nil +} + +// SetUserData - Set user data as a key/value couple. +// Can be retrieved through a HEAD request or an event. +func (p *PostPolicy) SetUserData(key string, value string) error { + if key == "" { + return ErrInvalidArgument("Key is empty") + } + if value == "" { + return ErrInvalidArgument("Value is empty") + } + headerName := fmt.Sprintf("x-amz-%s", key) + policyCond := policyCondition{ + matchType: "eq", + condition: fmt.Sprintf("$%s", headerName), + value: value, + } + if err := p.addNewPolicy(policyCond); err != nil { + return err + } + p.formData[headerName] = value + return nil +} + +// addNewPolicy - internal helper to validate adding new policies. +func (p *PostPolicy) addNewPolicy(policyCond policyCondition) error { + if policyCond.matchType == "" || policyCond.condition == "" || policyCond.value == "" { + return ErrInvalidArgument("Policy fields are empty.") + } + p.conditions = append(p.conditions, policyCond) + return nil +} + +// Stringer interface for printing policy in json formatted string. +func (p PostPolicy) String() string { + return string(p.marshalJSON()) +} + +// marshalJSON - Provides Marshalled JSON in bytes. +func (p PostPolicy) marshalJSON() []byte { + expirationStr := `"expiration":"` + p.expiration.Format(expirationDateFormat) + `"` + var conditionsStr string + conditions := []string{} + for _, po := range p.conditions { + conditions = append(conditions, fmt.Sprintf("[\"%s\",\"%s\",\"%s\"]", po.matchType, po.condition, po.value)) + } + if p.contentLengthRange.min != 0 || p.contentLengthRange.max != 0 { + conditions = append(conditions, fmt.Sprintf("[\"content-length-range\", %d, %d]", + p.contentLengthRange.min, p.contentLengthRange.max)) + } + if len(conditions) > 0 { + conditionsStr = `"conditions":[` + strings.Join(conditions, ",") + "]" + } + retStr := "{" + retStr = retStr + expirationStr + "," + retStr = retStr + conditionsStr + retStr = retStr + "}" + return []byte(retStr) +} + +// base64 - Produces base64 of PostPolicy's Marshalled json. +func (p PostPolicy) base64() string { + return base64.StdEncoding.EncodeToString(p.marshalJSON()) +} diff --git a/vendor/github.com/minio/minio-go/retry-continous.go b/vendor/github.com/minio/minio-go/retry-continous.go new file mode 100644 index 0000000000000..f31dfa6f250f3 --- /dev/null +++ b/vendor/github.com/minio/minio-go/retry-continous.go @@ -0,0 +1,69 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2015-2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package minio + +import "time" + +// newRetryTimerContinous creates a timer with exponentially increasing delays forever. +func (c Client) newRetryTimerContinous(unit time.Duration, cap time.Duration, jitter float64, doneCh chan struct{}) <-chan int { + attemptCh := make(chan int) + + // normalize jitter to the range [0, 1.0] + if jitter < NoJitter { + jitter = NoJitter + } + if jitter > MaxJitter { + jitter = MaxJitter + } + + // computes the exponential backoff duration according to + // https://www.awsarchitectureblog.com/2015/03/backoff.html + exponentialBackoffWait := func(attempt int) time.Duration { + // 1< maxAttempt { + attempt = maxAttempt + } + //sleep = random_between(0, min(cap, base * 2 ** attempt)) + sleep := unit * time.Duration(1< cap { + sleep = cap + } + if jitter != NoJitter { + sleep -= time.Duration(c.random.Float64() * float64(sleep) * jitter) + } + return sleep + } + + go func() { + defer close(attemptCh) + var nextBackoff int + for { + select { + // Attempts starts. + case attemptCh <- nextBackoff: + nextBackoff++ + case <-doneCh: + // Stop the routine. + return + } + time.Sleep(exponentialBackoffWait(nextBackoff)) + } + }() + return attemptCh +} diff --git a/vendor/github.com/minio/minio-go/retry.go b/vendor/github.com/minio/minio-go/retry.go new file mode 100644 index 0000000000000..445167b6aff61 --- /dev/null +++ b/vendor/github.com/minio/minio-go/retry.go @@ -0,0 +1,153 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2015-2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package minio + +import ( + "net" + "net/http" + "net/url" + "strings" + "time" +) + +// MaxRetry is the maximum number of retries before stopping. +var MaxRetry = 10 + +// MaxJitter will randomize over the full exponential backoff time +const MaxJitter = 1.0 + +// NoJitter disables the use of jitter for randomizing the exponential backoff time +const NoJitter = 0.0 + +// DefaultRetryUnit - default unit multiplicative per retry. +// defaults to 1 second. +const DefaultRetryUnit = time.Second + +// DefaultRetryCap - Each retry attempt never waits no longer than +// this maximum time duration. +const DefaultRetryCap = time.Second * 30 + +// newRetryTimer creates a timer with exponentially increasing +// delays until the maximum retry attempts are reached. +func (c Client) newRetryTimer(maxRetry int, unit time.Duration, cap time.Duration, jitter float64, doneCh chan struct{}) <-chan int { + attemptCh := make(chan int) + + // computes the exponential backoff duration according to + // https://www.awsarchitectureblog.com/2015/03/backoff.html + exponentialBackoffWait := func(attempt int) time.Duration { + // normalize jitter to the range [0, 1.0] + if jitter < NoJitter { + jitter = NoJitter + } + if jitter > MaxJitter { + jitter = MaxJitter + } + + //sleep = random_between(0, min(cap, base * 2 ** attempt)) + sleep := unit * time.Duration(1< cap { + sleep = cap + } + if jitter != NoJitter { + sleep -= time.Duration(c.random.Float64() * float64(sleep) * jitter) + } + return sleep + } + + go func() { + defer close(attemptCh) + for i := 0; i < maxRetry; i++ { + select { + // Attempts start from 1. + case attemptCh <- i + 1: + case <-doneCh: + // Stop the routine. + return + } + time.Sleep(exponentialBackoffWait(i)) + } + }() + return attemptCh +} + +// isHTTPReqErrorRetryable - is http requests error retryable, such +// as i/o timeout, connection broken etc.. +func isHTTPReqErrorRetryable(err error) bool { + if err == nil { + return false + } + switch e := err.(type) { + case *url.Error: + switch e.Err.(type) { + case *net.DNSError, *net.OpError, net.UnknownNetworkError: + return true + } + if strings.Contains(err.Error(), "Connection closed by foreign host") { + return true + } else if strings.Contains(err.Error(), "net/http: TLS handshake timeout") { + // If error is - tlsHandshakeTimeoutError, retry. + return true + } else if strings.Contains(err.Error(), "i/o timeout") { + // If error is - tcp timeoutError, retry. + return true + } else if strings.Contains(err.Error(), "connection timed out") { + // If err is a net.Dial timeout, retry. + return true + } else if strings.Contains(err.Error(), "net/http: HTTP/1.x transport connection broken") { + // If error is transport connection broken, retry. + return true + } + } + return false +} + +// List of AWS S3 error codes which are retryable. +var retryableS3Codes = map[string]struct{}{ + "RequestError": {}, + "RequestTimeout": {}, + "Throttling": {}, + "ThrottlingException": {}, + "RequestLimitExceeded": {}, + "RequestThrottled": {}, + "InternalError": {}, + "ExpiredToken": {}, + "ExpiredTokenException": {}, + "SlowDown": {}, + // Add more AWS S3 codes here. +} + +// isS3CodeRetryable - is s3 error code retryable. +func isS3CodeRetryable(s3Code string) (ok bool) { + _, ok = retryableS3Codes[s3Code] + return ok +} + +// List of HTTP status codes which are retryable. +var retryableHTTPStatusCodes = map[int]struct{}{ + 429: {}, // http.StatusTooManyRequests is not part of the Go 1.5 library, yet + http.StatusInternalServerError: {}, + http.StatusBadGateway: {}, + http.StatusServiceUnavailable: {}, + // Add more HTTP status codes here. +} + +// isHTTPStatusRetryable - is HTTP error code retryable. +func isHTTPStatusRetryable(httpStatusCode int) (ok bool) { + _, ok = retryableHTTPStatusCodes[httpStatusCode] + return ok +} diff --git a/vendor/github.com/minio/minio-go/s3-endpoints.go b/vendor/github.com/minio/minio-go/s3-endpoints.go new file mode 100644 index 0000000000000..0eccd24070b94 --- /dev/null +++ b/vendor/github.com/minio/minio-go/s3-endpoints.go @@ -0,0 +1,52 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2015-2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package minio + +// awsS3EndpointMap Amazon S3 endpoint map. +var awsS3EndpointMap = map[string]string{ + "us-east-1": "s3.dualstack.us-east-1.amazonaws.com", + "us-east-2": "s3.dualstack.us-east-2.amazonaws.com", + "us-west-2": "s3.dualstack.us-west-2.amazonaws.com", + "us-west-1": "s3.dualstack.us-west-1.amazonaws.com", + "ca-central-1": "s3.dualstack.ca-central-1.amazonaws.com", + "eu-west-1": "s3.dualstack.eu-west-1.amazonaws.com", + "eu-west-2": "s3.dualstack.eu-west-2.amazonaws.com", + "eu-west-3": "s3.dualstack.eu-west-3.amazonaws.com", + "eu-central-1": "s3.dualstack.eu-central-1.amazonaws.com", + "eu-north-1": "s3.dualstack.eu-north-1.amazonaws.com", + "ap-south-1": "s3.dualstack.ap-south-1.amazonaws.com", + "ap-southeast-1": "s3.dualstack.ap-southeast-1.amazonaws.com", + "ap-southeast-2": "s3.dualstack.ap-southeast-2.amazonaws.com", + "ap-northeast-1": "s3.dualstack.ap-northeast-1.amazonaws.com", + "ap-northeast-2": "s3.dualstack.ap-northeast-2.amazonaws.com", + "sa-east-1": "s3.dualstack.sa-east-1.amazonaws.com", + "us-gov-west-1": "s3.dualstack.us-gov-west-1.amazonaws.com", + "us-gov-east-1": "s3.dualstack.us-gov-east-1.amazonaws.com", + "cn-north-1": "s3.cn-north-1.amazonaws.com.cn", + "cn-northwest-1": "s3.cn-northwest-1.amazonaws.com.cn", +} + +// getS3Endpoint get Amazon S3 endpoint based on the bucket location. +func getS3Endpoint(bucketLocation string) (s3Endpoint string) { + s3Endpoint, ok := awsS3EndpointMap[bucketLocation] + if !ok { + // Default to 's3.dualstack.us-east-1.amazonaws.com' endpoint. + s3Endpoint = "s3.dualstack.us-east-1.amazonaws.com" + } + return s3Endpoint +} diff --git a/vendor/github.com/minio/minio-go/s3-error.go b/vendor/github.com/minio/minio-go/s3-error.go new file mode 100644 index 0000000000000..3b11776c2c039 --- /dev/null +++ b/vendor/github.com/minio/minio-go/s3-error.go @@ -0,0 +1,61 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2015-2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package minio + +// Non exhaustive list of AWS S3 standard error responses - +// http://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html +var s3ErrorResponseMap = map[string]string{ + "AccessDenied": "Access Denied.", + "BadDigest": "The Content-Md5 you specified did not match what we received.", + "EntityTooSmall": "Your proposed upload is smaller than the minimum allowed object size.", + "EntityTooLarge": "Your proposed upload exceeds the maximum allowed object size.", + "IncompleteBody": "You did not provide the number of bytes specified by the Content-Length HTTP header.", + "InternalError": "We encountered an internal error, please try again.", + "InvalidAccessKeyId": "The access key ID you provided does not exist in our records.", + "InvalidBucketName": "The specified bucket is not valid.", + "InvalidDigest": "The Content-Md5 you specified is not valid.", + "InvalidRange": "The requested range is not satisfiable", + "MalformedXML": "The XML you provided was not well-formed or did not validate against our published schema.", + "MissingContentLength": "You must provide the Content-Length HTTP header.", + "MissingContentMD5": "Missing required header for this request: Content-Md5.", + "MissingRequestBodyError": "Request body is empty.", + "NoSuchBucket": "The specified bucket does not exist.", + "NoSuchBucketPolicy": "The bucket policy does not exist", + "NoSuchKey": "The specified key does not exist.", + "NoSuchUpload": "The specified multipart upload does not exist. The upload ID may be invalid, or the upload may have been aborted or completed.", + "NotImplemented": "A header you provided implies functionality that is not implemented", + "PreconditionFailed": "At least one of the pre-conditions you specified did not hold", + "RequestTimeTooSkewed": "The difference between the request time and the server's time is too large.", + "SignatureDoesNotMatch": "The request signature we calculated does not match the signature you provided. Check your key and signing method.", + "MethodNotAllowed": "The specified method is not allowed against this resource.", + "InvalidPart": "One or more of the specified parts could not be found.", + "InvalidPartOrder": "The list of parts was not in ascending order. The parts list must be specified in order by part number.", + "InvalidObjectState": "The operation is not valid for the current state of the object.", + "AuthorizationHeaderMalformed": "The authorization header is malformed; the region is wrong.", + "MalformedPOSTRequest": "The body of your POST request is not well-formed multipart/form-data.", + "BucketNotEmpty": "The bucket you tried to delete is not empty", + "AllAccessDisabled": "All access to this bucket has been disabled.", + "MalformedPolicy": "Policy has invalid resource.", + "MissingFields": "Missing fields in request.", + "AuthorizationQueryParametersError": "Error parsing the X-Amz-Credential parameter; the Credential is mal-formed; expecting \"/YYYYMMDD/REGION/SERVICE/aws4_request\".", + "MalformedDate": "Invalid date format header, expected to be in ISO8601, RFC1123 or RFC1123Z time format.", + "BucketAlreadyOwnedByYou": "Your previous request to create the named bucket succeeded and you already own it.", + "InvalidDuration": "Duration provided in the request is invalid.", + "XAmzContentSHA256Mismatch": "The provided 'x-amz-content-sha256' header does not match what was computed.", + // Add new API errors here. +} diff --git a/vendor/github.com/minio/minio-go/transport.go b/vendor/github.com/minio/minio-go/transport.go new file mode 100644 index 0000000000000..88700cfe71a4e --- /dev/null +++ b/vendor/github.com/minio/minio-go/transport.go @@ -0,0 +1,50 @@ +// +build go1.7 go1.8 + +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2017-2018 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package minio + +import ( + "net" + "net/http" + "time" +) + +// DefaultTransport - this default transport is similar to +// http.DefaultTransport but with additional param DisableCompression +// is set to true to avoid decompressing content with 'gzip' encoding. +var DefaultTransport http.RoundTripper = &http.Transport{ + Proxy: http.ProxyFromEnvironment, + DialContext: (&net.Dialer{ + Timeout: 30 * time.Second, + KeepAlive: 30 * time.Second, + DualStack: true, + }).DialContext, + MaxIdleConns: 100, + MaxIdleConnsPerHost: 100, + IdleConnTimeout: 90 * time.Second, + TLSHandshakeTimeout: 10 * time.Second, + ExpectContinueTimeout: 1 * time.Second, + // Set this value so that the underlying transport round-tripper + // doesn't try to auto decode the body of objects with + // content-encoding set to `gzip`. + // + // Refer: + // https://golang.org/src/net/http/transport.go?h=roundTrip#L1843 + DisableCompression: true, +} diff --git a/vendor/github.com/minio/minio-go/utils.go b/vendor/github.com/minio/minio-go/utils.go new file mode 100644 index 0000000000000..8483f38344f6e --- /dev/null +++ b/vendor/github.com/minio/minio-go/utils.go @@ -0,0 +1,272 @@ +/* + * Minio Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2015-2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package minio + +import ( + "crypto/md5" + "crypto/sha256" + "encoding/base64" + "encoding/hex" + "encoding/xml" + "io" + "io/ioutil" + "net" + "net/http" + "net/url" + "regexp" + "strings" + "time" + + "github.com/minio/minio-go/pkg/s3utils" +) + +// xmlDecoder provide decoded value in xml. +func xmlDecoder(body io.Reader, v interface{}) error { + d := xml.NewDecoder(body) + return d.Decode(v) +} + +// sum256 calculate sha256sum for an input byte array, returns hex encoded. +func sum256Hex(data []byte) string { + hash := sha256.New() + hash.Write(data) + return hex.EncodeToString(hash.Sum(nil)) +} + +// sumMD5Base64 calculate md5sum for an input byte array, returns base64 encoded. +func sumMD5Base64(data []byte) string { + hash := md5.New() + hash.Write(data) + return base64.StdEncoding.EncodeToString(hash.Sum(nil)) +} + +// getEndpointURL - construct a new endpoint. +func getEndpointURL(endpoint string, secure bool) (*url.URL, error) { + if strings.Contains(endpoint, ":") { + host, _, err := net.SplitHostPort(endpoint) + if err != nil { + return nil, err + } + if !s3utils.IsValidIP(host) && !s3utils.IsValidDomain(host) { + msg := "Endpoint: " + endpoint + " does not follow ip address or domain name standards." + return nil, ErrInvalidArgument(msg) + } + } else { + if !s3utils.IsValidIP(endpoint) && !s3utils.IsValidDomain(endpoint) { + msg := "Endpoint: " + endpoint + " does not follow ip address or domain name standards." + return nil, ErrInvalidArgument(msg) + } + } + // If secure is false, use 'http' scheme. + scheme := "https" + if !secure { + scheme = "http" + } + + // Construct a secured endpoint URL. + endpointURLStr := scheme + "://" + endpoint + endpointURL, err := url.Parse(endpointURLStr) + if err != nil { + return nil, err + } + + // Validate incoming endpoint URL. + if err := isValidEndpointURL(*endpointURL); err != nil { + return nil, err + } + return endpointURL, nil +} + +// closeResponse close non nil response with any response Body. +// convenient wrapper to drain any remaining data on response body. +// +// Subsequently this allows golang http RoundTripper +// to re-use the same connection for future requests. +func closeResponse(resp *http.Response) { + // Callers should close resp.Body when done reading from it. + // If resp.Body is not closed, the Client's underlying RoundTripper + // (typically Transport) may not be able to re-use a persistent TCP + // connection to the server for a subsequent "keep-alive" request. + if resp != nil && resp.Body != nil { + // Drain any remaining Body and then close the connection. + // Without this closing connection would disallow re-using + // the same connection for future uses. + // - http://stackoverflow.com/a/17961593/4465767 + io.Copy(ioutil.Discard, resp.Body) + resp.Body.Close() + } +} + +var ( + // Hex encoded string of nil sha256sum bytes. + emptySHA256Hex = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + + // Sentinel URL is the default url value which is invalid. + sentinelURL = url.URL{} +) + +// Verify if input endpoint URL is valid. +func isValidEndpointURL(endpointURL url.URL) error { + if endpointURL == sentinelURL { + return ErrInvalidArgument("Endpoint url cannot be empty.") + } + if endpointURL.Path != "/" && endpointURL.Path != "" { + return ErrInvalidArgument("Endpoint url cannot have fully qualified paths.") + } + if strings.Contains(endpointURL.Host, ".s3.amazonaws.com") { + if !s3utils.IsAmazonEndpoint(endpointURL) { + return ErrInvalidArgument("Amazon S3 endpoint should be 's3.amazonaws.com'.") + } + } + if strings.Contains(endpointURL.Host, ".googleapis.com") { + if !s3utils.IsGoogleEndpoint(endpointURL) { + return ErrInvalidArgument("Google Cloud Storage endpoint should be 'storage.googleapis.com'.") + } + } + return nil +} + +// Verify if input expires value is valid. +func isValidExpiry(expires time.Duration) error { + expireSeconds := int64(expires / time.Second) + if expireSeconds < 1 { + return ErrInvalidArgument("Expires cannot be lesser than 1 second.") + } + if expireSeconds > 604800 { + return ErrInvalidArgument("Expires cannot be greater than 7 days.") + } + return nil +} + +// make a copy of http.Header +func cloneHeader(h http.Header) http.Header { + h2 := make(http.Header, len(h)) + for k, vv := range h { + vv2 := make([]string, len(vv)) + copy(vv2, vv) + h2[k] = vv2 + } + return h2 +} + +// Filter relevant response headers from +// the HEAD, GET http response. The function takes +// a list of headers which are filtered out and +// returned as a new http header. +func filterHeader(header http.Header, filterKeys []string) (filteredHeader http.Header) { + filteredHeader = cloneHeader(header) + for _, key := range filterKeys { + filteredHeader.Del(key) + } + return filteredHeader +} + +// regCred matches credential string in HTTP header +var regCred = regexp.MustCompile("Credential=([A-Z0-9]+)/") + +// regCred matches signature string in HTTP header +var regSign = regexp.MustCompile("Signature=([[0-9a-f]+)") + +// Redact out signature value from authorization string. +func redactSignature(origAuth string) string { + if !strings.HasPrefix(origAuth, signV4Algorithm) { + // Set a temporary redacted auth + return "AWS **REDACTED**:**REDACTED**" + } + + /// Signature V4 authorization header. + + // Strip out accessKeyID from: + // Credential=////aws4_request + newAuth := regCred.ReplaceAllString(origAuth, "Credential=**REDACTED**/") + + // Strip out 256-bit signature from: Signature=<256-bit signature> + return regSign.ReplaceAllString(newAuth, "Signature=**REDACTED**") +} + +// Get default location returns the location based on the input +// URL `u`, if region override is provided then all location +// defaults to regionOverride. +// +// If no other cases match then the location is set to `us-east-1` +// as a last resort. +func getDefaultLocation(u url.URL, regionOverride string) (location string) { + if regionOverride != "" { + return regionOverride + } + region := s3utils.GetRegionFromURL(u) + if region == "" { + region = "us-east-1" + } + return region +} + +var supportedHeaders = []string{ + "content-type", + "cache-control", + "content-encoding", + "content-disposition", + "content-language", + "x-amz-website-redirect-location", + "expires", + // Add more supported headers here. +} + +// isStorageClassHeader returns true if the header is a supported storage class header +func isStorageClassHeader(headerKey string) bool { + return strings.ToLower(amzStorageClass) == strings.ToLower(headerKey) +} + +// isStandardHeader returns true if header is a supported header and not a custom header +func isStandardHeader(headerKey string) bool { + key := strings.ToLower(headerKey) + for _, header := range supportedHeaders { + if strings.ToLower(header) == key { + return true + } + } + return false +} + +// sseHeaders is list of server side encryption headers +var sseHeaders = []string{ + "x-amz-server-side-encryption", + "x-amz-server-side-encryption-aws-kms-key-id", + "x-amz-server-side-encryption-context", + "x-amz-server-side-encryption-customer-algorithm", + "x-amz-server-side-encryption-customer-key", + "x-amz-server-side-encryption-customer-key-MD5", +} + +// isSSEHeader returns true if header is a server side encryption header. +func isSSEHeader(headerKey string) bool { + key := strings.ToLower(headerKey) + for _, h := range sseHeaders { + if strings.ToLower(h) == key { + return true + } + } + return false +} + +// isAmzHeader returns true if header is a x-amz-meta-* or x-amz-acl header. +func isAmzHeader(headerKey string) bool { + key := strings.ToLower(headerKey) + + return strings.HasPrefix(key, "x-amz-meta-") || strings.HasPrefix(key, "x-amz-grant-") || key == "x-amz-acl" || isSSEHeader(headerKey) +} diff --git a/vendor/golang.org/x/net/http/httpguts/guts.go b/vendor/golang.org/x/net/http/httpguts/guts.go new file mode 100644 index 0000000000000..e6cd0ced39283 --- /dev/null +++ b/vendor/golang.org/x/net/http/httpguts/guts.go @@ -0,0 +1,50 @@ +// Copyright 2018 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 httpguts provides functions implementing various details +// of the HTTP specification. +// +// This package is shared by the standard library (which vendors it) +// and x/net/http2. It comes with no API stability promise. +package httpguts + +import ( + "net/textproto" + "strings" +) + +// ValidTrailerHeader reports whether name is a valid header field name to appear +// in trailers. +// See RFC 7230, Section 4.1.2 +func ValidTrailerHeader(name string) bool { + name = textproto.CanonicalMIMEHeaderKey(name) + if strings.HasPrefix(name, "If-") || badTrailer[name] { + return false + } + return true +} + +var badTrailer = map[string]bool{ + "Authorization": true, + "Cache-Control": true, + "Connection": true, + "Content-Encoding": true, + "Content-Length": true, + "Content-Range": true, + "Content-Type": true, + "Expect": true, + "Host": true, + "Keep-Alive": true, + "Max-Forwards": true, + "Pragma": true, + "Proxy-Authenticate": true, + "Proxy-Authorization": true, + "Proxy-Connection": true, + "Range": true, + "Realm": true, + "Te": true, + "Trailer": true, + "Transfer-Encoding": true, + "Www-Authenticate": true, +} diff --git a/vendor/golang.org/x/net/http/httpguts/httplex.go b/vendor/golang.org/x/net/http/httpguts/httplex.go new file mode 100644 index 0000000000000..e7de24ee64efc --- /dev/null +++ b/vendor/golang.org/x/net/http/httpguts/httplex.go @@ -0,0 +1,346 @@ +// Copyright 2016 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 httpguts + +import ( + "net" + "strings" + "unicode/utf8" + + "golang.org/x/net/idna" +) + +var isTokenTable = [127]bool{ + '!': true, + '#': true, + '$': true, + '%': true, + '&': true, + '\'': true, + '*': true, + '+': true, + '-': true, + '.': true, + '0': true, + '1': true, + '2': true, + '3': true, + '4': true, + '5': true, + '6': true, + '7': true, + '8': true, + '9': true, + 'A': true, + 'B': true, + 'C': true, + 'D': true, + 'E': true, + 'F': true, + 'G': true, + 'H': true, + 'I': true, + 'J': true, + 'K': true, + 'L': true, + 'M': true, + 'N': true, + 'O': true, + 'P': true, + 'Q': true, + 'R': true, + 'S': true, + 'T': true, + 'U': true, + 'W': true, + 'V': true, + 'X': true, + 'Y': true, + 'Z': true, + '^': true, + '_': true, + '`': true, + 'a': true, + 'b': true, + 'c': true, + 'd': true, + 'e': true, + 'f': true, + 'g': true, + 'h': true, + 'i': true, + 'j': true, + 'k': true, + 'l': true, + 'm': true, + 'n': true, + 'o': true, + 'p': true, + 'q': true, + 'r': true, + 's': true, + 't': true, + 'u': true, + 'v': true, + 'w': true, + 'x': true, + 'y': true, + 'z': true, + '|': true, + '~': true, +} + +func IsTokenRune(r rune) bool { + i := int(r) + return i < len(isTokenTable) && isTokenTable[i] +} + +func isNotToken(r rune) bool { + return !IsTokenRune(r) +} + +// HeaderValuesContainsToken reports whether any string in values +// contains the provided token, ASCII case-insensitively. +func HeaderValuesContainsToken(values []string, token string) bool { + for _, v := range values { + if headerValueContainsToken(v, token) { + return true + } + } + return false +} + +// isOWS reports whether b is an optional whitespace byte, as defined +// by RFC 7230 section 3.2.3. +func isOWS(b byte) bool { return b == ' ' || b == '\t' } + +// trimOWS returns x with all optional whitespace removes from the +// beginning and end. +func trimOWS(x string) string { + // TODO: consider using strings.Trim(x, " \t") instead, + // if and when it's fast enough. See issue 10292. + // But this ASCII-only code will probably always beat UTF-8 + // aware code. + for len(x) > 0 && isOWS(x[0]) { + x = x[1:] + } + for len(x) > 0 && isOWS(x[len(x)-1]) { + x = x[:len(x)-1] + } + return x +} + +// headerValueContainsToken reports whether v (assumed to be a +// 0#element, in the ABNF extension described in RFC 7230 section 7) +// contains token amongst its comma-separated tokens, ASCII +// case-insensitively. +func headerValueContainsToken(v string, token string) bool { + v = trimOWS(v) + if comma := strings.IndexByte(v, ','); comma != -1 { + return tokenEqual(trimOWS(v[:comma]), token) || headerValueContainsToken(v[comma+1:], token) + } + return tokenEqual(v, token) +} + +// lowerASCII returns the ASCII lowercase version of b. +func lowerASCII(b byte) byte { + if 'A' <= b && b <= 'Z' { + return b + ('a' - 'A') + } + return b +} + +// tokenEqual reports whether t1 and t2 are equal, ASCII case-insensitively. +func tokenEqual(t1, t2 string) bool { + if len(t1) != len(t2) { + return false + } + for i, b := range t1 { + if b >= utf8.RuneSelf { + // No UTF-8 or non-ASCII allowed in tokens. + return false + } + if lowerASCII(byte(b)) != lowerASCII(t2[i]) { + return false + } + } + return true +} + +// isLWS reports whether b is linear white space, according +// to http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2 +// LWS = [CRLF] 1*( SP | HT ) +func isLWS(b byte) bool { return b == ' ' || b == '\t' } + +// isCTL reports whether b is a control byte, according +// to http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2 +// CTL = +func isCTL(b byte) bool { + const del = 0x7f // a CTL + return b < ' ' || b == del +} + +// ValidHeaderFieldName reports whether v is a valid HTTP/1.x header name. +// HTTP/2 imposes the additional restriction that uppercase ASCII +// letters are not allowed. +// +// RFC 7230 says: +// header-field = field-name ":" OWS field-value OWS +// field-name = token +// token = 1*tchar +// tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." / +// "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA +func ValidHeaderFieldName(v string) bool { + if len(v) == 0 { + return false + } + for _, r := range v { + if !IsTokenRune(r) { + return false + } + } + return true +} + +// ValidHostHeader reports whether h is a valid host header. +func ValidHostHeader(h string) bool { + // The latest spec is actually this: + // + // http://tools.ietf.org/html/rfc7230#section-5.4 + // Host = uri-host [ ":" port ] + // + // Where uri-host is: + // http://tools.ietf.org/html/rfc3986#section-3.2.2 + // + // But we're going to be much more lenient for now and just + // search for any byte that's not a valid byte in any of those + // expressions. + for i := 0; i < len(h); i++ { + if !validHostByte[h[i]] { + return false + } + } + return true +} + +// See the validHostHeader comment. +var validHostByte = [256]bool{ + '0': true, '1': true, '2': true, '3': true, '4': true, '5': true, '6': true, '7': true, + '8': true, '9': true, + + 'a': true, 'b': true, 'c': true, 'd': true, 'e': true, 'f': true, 'g': true, 'h': true, + 'i': true, 'j': true, 'k': true, 'l': true, 'm': true, 'n': true, 'o': true, 'p': true, + 'q': true, 'r': true, 's': true, 't': true, 'u': true, 'v': true, 'w': true, 'x': true, + 'y': true, 'z': true, + + 'A': true, 'B': true, 'C': true, 'D': true, 'E': true, 'F': true, 'G': true, 'H': true, + 'I': true, 'J': true, 'K': true, 'L': true, 'M': true, 'N': true, 'O': true, 'P': true, + 'Q': true, 'R': true, 'S': true, 'T': true, 'U': true, 'V': true, 'W': true, 'X': true, + 'Y': true, 'Z': true, + + '!': true, // sub-delims + '$': true, // sub-delims + '%': true, // pct-encoded (and used in IPv6 zones) + '&': true, // sub-delims + '(': true, // sub-delims + ')': true, // sub-delims + '*': true, // sub-delims + '+': true, // sub-delims + ',': true, // sub-delims + '-': true, // unreserved + '.': true, // unreserved + ':': true, // IPv6address + Host expression's optional port + ';': true, // sub-delims + '=': true, // sub-delims + '[': true, + '\'': true, // sub-delims + ']': true, + '_': true, // unreserved + '~': true, // unreserved +} + +// ValidHeaderFieldValue reports whether v is a valid "field-value" according to +// http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 : +// +// message-header = field-name ":" [ field-value ] +// field-value = *( field-content | LWS ) +// field-content = +// +// http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2 : +// +// TEXT = +// LWS = [CRLF] 1*( SP | HT ) +// CTL = +// +// RFC 7230 says: +// field-value = *( field-content / obs-fold ) +// obj-fold = N/A to http2, and deprecated +// field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ] +// field-vchar = VCHAR / obs-text +// obs-text = %x80-FF +// VCHAR = "any visible [USASCII] character" +// +// http2 further says: "Similarly, HTTP/2 allows header field values +// that are not valid. While most of the values that can be encoded +// will not alter header field parsing, carriage return (CR, ASCII +// 0xd), line feed (LF, ASCII 0xa), and the zero character (NUL, ASCII +// 0x0) might be exploited by an attacker if they are translated +// verbatim. Any request or response that contains a character not +// permitted in a header field value MUST be treated as malformed +// (Section 8.1.2.6). Valid characters are defined by the +// field-content ABNF rule in Section 3.2 of [RFC7230]." +// +// This function does not (yet?) properly handle the rejection of +// strings that begin or end with SP or HTAB. +func ValidHeaderFieldValue(v string) bool { + for i := 0; i < len(v); i++ { + b := v[i] + if isCTL(b) && !isLWS(b) { + return false + } + } + return true +} + +func isASCII(s string) bool { + for i := 0; i < len(s); i++ { + if s[i] >= utf8.RuneSelf { + return false + } + } + return true +} + +// PunycodeHostPort returns the IDNA Punycode version +// of the provided "host" or "host:port" string. +func PunycodeHostPort(v string) (string, error) { + if isASCII(v) { + return v, nil + } + + host, port, err := net.SplitHostPort(v) + if err != nil { + // The input 'v' argument was just a "host" argument, + // without a port. This error should not be returned + // to the caller. + host = v + port = "" + } + host, err = idna.ToASCII(host) + if err != nil { + // Non-UTF-8? Not representable in Punycode, in any + // case. + return "", err + } + if port == "" { + return host, nil + } + return net.JoinHostPort(host, port), nil +} diff --git a/vendor/golang.org/x/net/publicsuffix/list.go b/vendor/golang.org/x/net/publicsuffix/list.go new file mode 100644 index 0000000000000..200617ea86475 --- /dev/null +++ b/vendor/golang.org/x/net/publicsuffix/list.go @@ -0,0 +1,181 @@ +// Copyright 2012 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. + +//go:generate go run gen.go + +// Package publicsuffix provides a public suffix list based on data from +// https://publicsuffix.org/ +// +// A public suffix is one under which Internet users can directly register +// names. It is related to, but different from, a TLD (top level domain). +// +// "com" is a TLD (top level domain). Top level means it has no dots. +// +// "com" is also a public suffix. Amazon and Google have registered different +// siblings under that domain: "amazon.com" and "google.com". +// +// "au" is another TLD, again because it has no dots. But it's not "amazon.au". +// Instead, it's "amazon.com.au". +// +// "com.au" isn't an actual TLD, because it's not at the top level (it has +// dots). But it is an eTLD (effective TLD), because that's the branching point +// for domain name registrars. +// +// Another name for "an eTLD" is "a public suffix". Often, what's more of +// interest is the eTLD+1, or one more label than the public suffix. For +// example, browsers partition read/write access to HTTP cookies according to +// the eTLD+1. Web pages served from "amazon.com.au" can't read cookies from +// "google.com.au", but web pages served from "maps.google.com" can share +// cookies from "www.google.com", so you don't have to sign into Google Maps +// separately from signing into Google Web Search. Note that all four of those +// domains have 3 labels and 2 dots. The first two domains are each an eTLD+1, +// the last two are not (but share the same eTLD+1: "google.com"). +// +// All of these domains have the same eTLD+1: +// - "www.books.amazon.co.uk" +// - "books.amazon.co.uk" +// - "amazon.co.uk" +// Specifically, the eTLD+1 is "amazon.co.uk", because the eTLD is "co.uk". +// +// There is no closed form algorithm to calculate the eTLD of a domain. +// Instead, the calculation is data driven. This package provides a +// pre-compiled snapshot of Mozilla's PSL (Public Suffix List) data at +// https://publicsuffix.org/ +package publicsuffix // import "golang.org/x/net/publicsuffix" + +// TODO: specify case sensitivity and leading/trailing dot behavior for +// func PublicSuffix and func EffectiveTLDPlusOne. + +import ( + "fmt" + "net/http/cookiejar" + "strings" +) + +// List implements the cookiejar.PublicSuffixList interface by calling the +// PublicSuffix function. +var List cookiejar.PublicSuffixList = list{} + +type list struct{} + +func (list) PublicSuffix(domain string) string { + ps, _ := PublicSuffix(domain) + return ps +} + +func (list) String() string { + return version +} + +// PublicSuffix returns the public suffix of the domain using a copy of the +// publicsuffix.org database compiled into the library. +// +// icann is whether the public suffix is managed by the Internet Corporation +// for Assigned Names and Numbers. If not, the public suffix is either a +// privately managed domain (and in practice, not a top level domain) or an +// unmanaged top level domain (and not explicitly mentioned in the +// publicsuffix.org list). For example, "foo.org" and "foo.co.uk" are ICANN +// domains, "foo.dyndns.org" and "foo.blogspot.co.uk" are private domains and +// "cromulent" is an unmanaged top level domain. +// +// Use cases for distinguishing ICANN domains like "foo.com" from private +// domains like "foo.appspot.com" can be found at +// https://wiki.mozilla.org/Public_Suffix_List/Use_Cases +func PublicSuffix(domain string) (publicSuffix string, icann bool) { + lo, hi := uint32(0), uint32(numTLD) + s, suffix, icannNode, wildcard := domain, len(domain), false, false +loop: + for { + dot := strings.LastIndex(s, ".") + if wildcard { + icann = icannNode + suffix = 1 + dot + } + if lo == hi { + break + } + f := find(s[1+dot:], lo, hi) + if f == notFound { + break + } + + u := nodes[f] >> (nodesBitsTextOffset + nodesBitsTextLength) + icannNode = u&(1<>= nodesBitsICANN + u = children[u&(1<>= childrenBitsLo + hi = u & (1<>= childrenBitsHi + switch u & (1<>= childrenBitsNodeType + wildcard = u&(1<>= nodesBitsTextLength + offset := x & (1< Date: Tue, 12 May 2020 17:01:37 +0800 Subject: [PATCH 02/59] Fix some bug --- integrations/attachment_test.go | 8 +++----- models/repo.go | 2 +- modules/storage/local.go | 4 ++++ modules/storage/minio.go | 4 ++++ modules/storage/storage.go | 5 ++++- 5 files changed, 16 insertions(+), 7 deletions(-) diff --git a/integrations/attachment_test.go b/integrations/attachment_test.go index eda6fbdb57146..3dfc4faca21c0 100644 --- a/integrations/attachment_test.go +++ b/integrations/attachment_test.go @@ -9,14 +9,12 @@ import ( "image" "image/png" "io" - "io/ioutil" "mime/multipart" "net/http" - "os" - "path" + "strings" "testing" - "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/storage" "code.gitea.io/gitea/modules/test" "github.com/stretchr/testify/assert" @@ -123,7 +121,7 @@ func TestGetAttachment(t *testing.T) { t.Run(tc.name, func(t *testing.T) { //Write empty file to be available for response if tc.createFile { - err = SaveAttachment(tc.uuid, strings.NewReader("hello world")) + err = storage.Attachments.Save(tc.RelativePath(), strings.NewReader("hello world")) assert.NoError(t, err) } //Actual test diff --git a/models/repo.go b/models/repo.go index b9296e7b75ec8..b9ebec8be9329 100644 --- a/models/repo.go +++ b/models/repo.go @@ -1596,7 +1596,7 @@ func DeleteRepository(doer *User, uid, repoID int64) error { } releaseAttachments := make([]string, 0, len(attachments)) for i := 0; i < len(attachments); i++ { - releaseAttachments = append(releaseAttachments, attachments[i].UUID) + releaseAttachments = append(releaseAttachments, attachments[i].RelativePath()) } if _, err = sess.Exec("UPDATE `user` SET num_stars=num_stars-1 WHERE id IN (SELECT `uid` FROM `star` WHERE repo_id = ?)", repo.ID); err != nil { diff --git a/modules/storage/local.go b/modules/storage/local.go index 86f2bb58913c6..7a5f00e63685a 100644 --- a/modules/storage/local.go +++ b/modules/storage/local.go @@ -1,3 +1,7 @@ +// Copyright 2020 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + package storage import ( diff --git a/modules/storage/minio.go b/modules/storage/minio.go index 57f8d8a6b7b58..445ac546c07d4 100644 --- a/modules/storage/minio.go +++ b/modules/storage/minio.go @@ -1,3 +1,7 @@ +// Copyright 2020 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + package storage import ( diff --git a/modules/storage/storage.go b/modules/storage/storage.go index 5034a7d4b9d54..88e84137a2d81 100644 --- a/modules/storage/storage.go +++ b/modules/storage/storage.go @@ -1,3 +1,7 @@ +// Copyright 2020 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + package storage import ( @@ -39,4 +43,3 @@ func Init() error { return nil } - From d7a681bdd9b9da5f4b49152ae4cf59cc778e335a Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 12 May 2020 23:30:43 +0800 Subject: [PATCH 03/59] fix test --- integrations/attachment_test.go | 3 ++- models/attachment.go | 7 ++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/integrations/attachment_test.go b/integrations/attachment_test.go index 3dfc4faca21c0..533725a2a19be 100644 --- a/integrations/attachment_test.go +++ b/integrations/attachment_test.go @@ -14,6 +14,7 @@ import ( "strings" "testing" + "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/storage" "code.gitea.io/gitea/modules/test" @@ -121,7 +122,7 @@ func TestGetAttachment(t *testing.T) { t.Run(tc.name, func(t *testing.T) { //Write empty file to be available for response if tc.createFile { - err = storage.Attachments.Save(tc.RelativePath(), strings.NewReader("hello world")) + _, err := storage.Attachments.Save(models.AttachmentRelativePath(tc), strings.NewReader("hello world")) assert.NoError(t, err) } //Actual test diff --git a/models/attachment.go b/models/attachment.go index 3ec4219641fef..309b87fa27595 100644 --- a/models/attachment.go +++ b/models/attachment.go @@ -61,9 +61,14 @@ func (a *Attachment) DownloadURL() string { return fmt.Sprintf("%sattachments/%s", setting.AppURL, a.UUID) } +// AttachmentRelativePath returns the relative path +func AttachmentRelativePath(uuid string) string { + return path.Join(uuid[0:1], uuid[1:2], uuid) +} + // RelativePath returns the relative path of the attachment func (a *Attachment) RelativePath() string { - return path.Join(a.UUID[0:1], a.UUID[1:2], a.UUID) + return AttachmentRelativePath(a.UUID) } // LinkedRepository returns the linked repo if any From 0c3bad9d554b5ca162f74ff855ef60efb2a3a46f Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 13 May 2020 09:34:16 +0800 Subject: [PATCH 04/59] Fix copyright head and lint --- cmd/migrate_storage.go | 2 +- integrations/attachment_test.go | 2 +- models/admin.go | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/cmd/migrate_storage.go b/cmd/migrate_storage.go index 35c1b45052fe6..b92100135acd8 100644 --- a/cmd/migrate_storage.go +++ b/cmd/migrate_storage.go @@ -1,4 +1,4 @@ -// Copyright 2018 The Gitea Authors. All rights reserved. +// Copyright 2020 The Gitea Authors. All rights reserved. // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. diff --git a/integrations/attachment_test.go b/integrations/attachment_test.go index 533725a2a19be..7219adf7d75b4 100644 --- a/integrations/attachment_test.go +++ b/integrations/attachment_test.go @@ -122,7 +122,7 @@ func TestGetAttachment(t *testing.T) { t.Run(tc.name, func(t *testing.T) { //Write empty file to be available for response if tc.createFile { - _, err := storage.Attachments.Save(models.AttachmentRelativePath(tc), strings.NewReader("hello world")) + _, err := storage.Attachments.Save(models.AttachmentRelativePath(tc.uuid), strings.NewReader("hello world")) assert.NoError(t, err) } //Actual test diff --git a/models/admin.go b/models/admin.go index fbb6852581b8e..9ed9c44ebb390 100644 --- a/models/admin.go +++ b/models/admin.go @@ -1,4 +1,5 @@ // Copyright 2014 The Gogs Authors. All rights reserved. +// Copyright 2020 The Gitea Authors. All rights reserved. // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. From 96784da544732363c8cbdddcfaadfb1391f4877f Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 14 May 2020 21:50:49 +0800 Subject: [PATCH 05/59] Fix bug --- models/attachment.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/attachment.go b/models/attachment.go index 309b87fa27595..2da4223fccd02 100644 --- a/models/attachment.go +++ b/models/attachment.go @@ -219,7 +219,7 @@ func DeleteAttachments(attachments []*Attachment, remove bool) (int, error) { if remove { for i, a := range attachments { - if storage.Attachments.Delete(a.RelativePath()); err != nil { + if err := storage.Attachments.Delete(a.RelativePath()); err != nil { return i, err } } From 02354a1ac070228fceb789bac39b48dde04e5fb1 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 18 May 2020 00:26:45 +0800 Subject: [PATCH 06/59] Add setting for minio and flags for migrate-storage --- cmd/migrate_storage.go | 73 +++++++++++++++++++++-- modules/context/context.go | 2 +- modules/setting/setting.go | 66 ++++++++++++++++---- modules/storage/minio.go | 24 +++++--- modules/storage/storage.go | 20 ++++++- routers/api/v1/repo/release_attachment.go | 4 +- routers/repo/attachment.go | 13 ++-- routers/repo/issue.go | 4 +- routers/repo/pull.go | 2 +- routers/repo/release.go | 4 +- 10 files changed, 171 insertions(+), 41 deletions(-) diff --git a/cmd/migrate_storage.go b/cmd/migrate_storage.go index b92100135acd8..496f18e119191 100644 --- a/cmd/migrate_storage.go +++ b/cmd/migrate_storage.go @@ -6,6 +6,7 @@ package cmd import ( "context" + "fmt" "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/migrations" @@ -22,6 +23,53 @@ var CmdMigrateStorage = cli.Command{ Usage: "Migrate the storage", Description: "This is a command for migrating storage.", Action: runMigrateStorage, + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "type, t", + Value: "", + Usage: "Files type to migrate, currently should be attachments", + }, + cli.StringFlag{ + Name: "store, s", + Value: "local", + Usage: "New storage type, local or minio", + }, + cli.StringFlag{ + Name: "path, p", + Value: "", + Usage: "New storage placement if store is local", + }, + cli.StringFlag{ + Name: "minio-endpoint", + Value: "", + Usage: "New storage placement if store is local", + }, + cli.StringFlag{ + Name: "minio-access-key-id", + Value: "", + Usage: "New storage placement if store is local", + }, + cli.StringFlag{ + Name: "minio-scret-access-key", + Value: "", + Usage: "New storage placement if store is local", + }, + cli.StringFlag{ + Name: "minio-bucket", + Value: "", + Usage: "New storage placement if store is local", + }, + cli.StringFlag{ + Name: "minio-location", + Value: "", + Usage: "New storage placement if store is local", + }, + cli.StringFlag{ + Name: "minio-use-ssl", + Value: "", + Usage: "New storage placement if store is local", + }, + }, } func migrateAttachments(dstStorage storage.ObjectStorage) error { @@ -47,17 +95,32 @@ func runMigrateStorage(ctx *cli.Context) error { return err } - tp := ctx.String("type") - - // TODO: init setting - if err := storage.Init(); err != nil { return err } + tp := ctx.String("type") switch tp { case "attachments": - dstStorage, err := storage.NewLocalStorage(ctx.String("dst")) + var dstStorage storage.ObjectStorage + var err error + switch ctx.String("store") { + case "local": + dstStorage, err = storage.NewLocalStorage(ctx.String("dst")) + case "minio": + dstStorage, err = storage.NewMinioStorage( + ctx.String("minio-endpoint"), + ctx.String("minio-access-key-id"), + ctx.String("minio-secret-access-key"), + ctx.String("minio-bucket"), + ctx.String("minio-location"), + ctx.String("minio-basePath"), + ctx.Bool("minio-useSSL"), + ) + default: + return fmt.Errorf("Unsupported attachments store type: %s", ctx.String("store")) + } + if err != nil { return err } diff --git a/modules/context/context.go b/modules/context/context.go index cc68fb093b079..1405860e07d8c 100644 --- a/modules/context/context.go +++ b/modules/context/context.go @@ -319,7 +319,7 @@ func Contexter() macaron.Handler { // If request sends files, parse them here otherwise the Query() can't be parsed and the CsrfToken will be invalid. if ctx.Req.Method == "POST" && strings.Contains(ctx.Req.Header.Get("Content-Type"), "multipart/form-data") { - if err := ctx.Req.ParseMultipartForm(setting.AttachmentMaxSize << 20); err != nil && !strings.Contains(err.Error(), "EOF") { // 32MB max size + if err := ctx.Req.ParseMultipartForm(setting.Attachment.MaxSize << 20); err != nil && !strings.Contains(err.Error(), "EOF") { // 32MB max size ctx.ServerError("ParseMultipartForm", err) return } diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 33854a23000c7..bdb9db2103ae2 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -300,11 +300,38 @@ var ( EnableXORMLog bool // Attachment settings - AttachmentPath string - AttachmentAllowedTypes string - AttachmentMaxSize int64 - AttachmentMaxFiles int - AttachmentEnabled bool + Attachment = struct { + StoreType string + Path string + Minio struct { + Endpoint string + AccessKeyID string + SecretAccessKey string + UseSSL bool + Bucket string + Location string + BasePath string + } + AllowedTypes string + MaxSize int64 + MaxFiles int + Enabled bool + }{ + StoreType: "local", + Minio: struct { + Endpoint string + AccessKeyID string + SecretAccessKey string + UseSSL bool + Bucket string + Location string + BasePath string + }{}, + AllowedTypes: "image/jpeg,image/png,application/zip,application/gzip", + MaxSize: 4, + MaxFiles: 5, + Enabled: true, + } // Time settings TimeFormat string @@ -841,14 +868,27 @@ func NewContext() { } sec = Cfg.Section("attachment") - AttachmentPath = sec.Key("PATH").MustString(path.Join(AppDataPath, "attachments")) - if !filepath.IsAbs(AttachmentPath) { - AttachmentPath = path.Join(AppWorkPath, AttachmentPath) - } - AttachmentAllowedTypes = strings.Replace(sec.Key("ALLOWED_TYPES").MustString("image/jpeg,image/png,application/zip,application/gzip"), "|", ",", -1) - AttachmentMaxSize = sec.Key("MAX_SIZE").MustInt64(4) - AttachmentMaxFiles = sec.Key("MAX_FILES").MustInt(5) - AttachmentEnabled = sec.Key("ENABLED").MustBool(true) + Attachment.StoreType = sec.Key("STORE_TYPE").MustString("local") + switch Attachment.StoreType { + case "local": + Attachment.Path = sec.Key("PATH").MustString(path.Join(AppDataPath, "attachments")) + if !filepath.IsAbs(Attachment.Path) { + Attachment.Path = path.Join(AppWorkPath, Attachment.Path) + } + case "minio": + Attachment.Minio.Endpoint = sec.Key("MINIO_ENDPOINT").MustString("localhost:9000") + Attachment.Minio.AccessKeyID = sec.Key("MINIO_ACCESS_KEY_ID").MustString("") + Attachment.Minio.SecretAccessKey = sec.Key("MINIO_SECRET_ACCESS_KEY").MustString("") + Attachment.Minio.Bucket = sec.Key("MINIO_BUCKET").MustString("gitea") + Attachment.Minio.Location = sec.Key("MINIO_LOCATION").MustString("us-east-1") + Attachment.Minio.BasePath = sec.Key("MINIO_BASE_PATH").MustString("attachments/") + Attachment.Minio.UseSSL = sec.Key("MINIO_USE_SSL").MustBool(false) + } + + Attachment.AllowedTypes = strings.Replace(sec.Key("ALLOWED_TYPES").MustString("image/jpeg,image/png,application/zip,application/gzip"), "|", ",", -1) + Attachment.MaxSize = sec.Key("MAX_SIZE").MustInt64(4) + Attachment.MaxFiles = sec.Key("MAX_FILES").MustInt(5) + Attachment.Enabled = sec.Key("ENABLED").MustBool(true) timeFormatKey := Cfg.Section("time").Key("FORMAT").MustString("") if timeFormatKey != "" { diff --git a/modules/storage/minio.go b/modules/storage/minio.go index 445ac546c07d4..46bac876c7394 100644 --- a/modules/storage/minio.go +++ b/modules/storage/minio.go @@ -6,6 +6,7 @@ package storage import ( "io" + "path" "strings" "github.com/minio/minio-go" @@ -18,34 +19,41 @@ var ( // MinioStorage returns a minio bucket storage type MinioStorage struct { client *minio.Client - location string bucket string + location string basePath string } // NewMinioStorage returns a minio storage -func NewMinioStorage(endpoint, accessKeyID, secretAccessKey, location, bucket, basePath string, useSSL bool) (*MinioStorage, error) { +func NewMinioStorage(endpoint, accessKeyID, secretAccessKey, bucket, location, basePath string, useSSL bool) (*MinioStorage, error) { minioClient, err := minio.New(endpoint, accessKeyID, secretAccessKey, useSSL) if err != nil { return nil, err } + if err := minioClient.MakeBucket(bucket, location); err != nil { + // Check to see if we already own this bucket (which happens if you run this twice) + exists, errBucketExists := minioClient.BucketExists(bucket) + if !exists || errBucketExists != nil { + return nil, err + } + } + return &MinioStorage{ - location: location, client: minioClient, bucket: bucket, basePath: basePath, }, nil } -func buildMinioPath(p string) string { - return strings.TrimPrefix(p, "/") +func (m *MinioStorage) buildMinioPath(p string) string { + return strings.TrimPrefix(path.Join(m.basePath, p), "/") } // Open open a file func (m *MinioStorage) Open(path string) (io.ReadCloser, error) { var opts = minio.GetObjectOptions{} - object, err := m.client.GetObject(m.bucket, buildMinioPath(path), opts) + object, err := m.client.GetObject(m.bucket, m.buildMinioPath(path), opts) if err != nil { return nil, err } @@ -54,10 +62,10 @@ func (m *MinioStorage) Open(path string) (io.ReadCloser, error) { // Save save a file to minio func (m *MinioStorage) Save(path string, r io.Reader) (int64, error) { - return m.client.PutObject(m.bucket, buildMinioPath(path), r, -1, minio.PutObjectOptions{ContentType: "application/octet-stream"}) + return m.client.PutObject(m.bucket, m.buildMinioPath(path), r, -1, minio.PutObjectOptions{ContentType: "application/octet-stream"}) } // Delete delete a file func (m *MinioStorage) Delete(path string) error { - return m.client.RemoveObject(m.bucket, buildMinioPath(path)) + return m.client.RemoveObject(m.bucket, m.buildMinioPath(path)) } diff --git a/modules/storage/storage.go b/modules/storage/storage.go index 88e84137a2d81..963b38d0fdbb2 100644 --- a/modules/storage/storage.go +++ b/modules/storage/storage.go @@ -5,6 +5,7 @@ package storage import ( + "fmt" "io" "code.gitea.io/gitea/modules/setting" @@ -36,7 +37,24 @@ var ( // Init init the stoarge func Init() error { var err error - Attachments, err = NewLocalStorage(setting.AttachmentPath) + switch setting.Attachment.StoreType { + case "local": + Attachments, err = NewLocalStorage(setting.Attachment.Path) + case "minio": + minio := setting.Attachment.Minio + Attachments, err = NewMinioStorage( + minio.Endpoint, + minio.AccessKeyID, + minio.SecretAccessKey, + minio.Bucket, + minio.Location, + minio.BasePath, + minio.UseSSL, + ) + default: + return fmt.Errorf("Unsupported attachment store type: %s", setting.Attachment.StoreType) + } + if err != nil { return err } diff --git a/routers/api/v1/repo/release_attachment.go b/routers/api/v1/repo/release_attachment.go index 6ba6489e27705..3d1084f211fdc 100644 --- a/routers/api/v1/repo/release_attachment.go +++ b/routers/api/v1/repo/release_attachment.go @@ -154,7 +154,7 @@ func CreateReleaseAttachment(ctx *context.APIContext) { // "$ref": "#/responses/error" // Check if attachments are enabled - if !setting.AttachmentEnabled { + if !setting.Attachment.Enabled { ctx.NotFound("Attachment is not enabled") return } @@ -182,7 +182,7 @@ func CreateReleaseAttachment(ctx *context.APIContext) { } // Check if the filetype is allowed by the settings - err = upload.VerifyAllowedContentType(buf, strings.Split(setting.AttachmentAllowedTypes, ",")) + err = upload.VerifyAllowedContentType(buf, strings.Split(setting.Attachment.AllowedTypes, ",")) if err != nil { ctx.Error(http.StatusBadRequest, "DetectContentType", err) return diff --git a/routers/repo/attachment.go b/routers/repo/attachment.go index 505468fee5b85..479e8b3951bea 100644 --- a/routers/repo/attachment.go +++ b/routers/repo/attachment.go @@ -18,15 +18,16 @@ import ( ) func renderAttachmentSettings(ctx *context.Context) { - ctx.Data["IsAttachmentEnabled"] = setting.AttachmentEnabled - ctx.Data["AttachmentAllowedTypes"] = setting.AttachmentAllowedTypes - ctx.Data["AttachmentMaxSize"] = setting.AttachmentMaxSize - ctx.Data["AttachmentMaxFiles"] = setting.AttachmentMaxFiles + ctx.Data["IsAttachmentEnabled"] = setting.Attachment.Enabled + ctx.Data["AttachmentStoreType"] = setting.Attachment.StoreType + ctx.Data["AttachmentAllowedTypes"] = setting.Attachment.AllowedTypes + ctx.Data["AttachmentMaxSize"] = setting.Attachment.MaxSize + ctx.Data["AttachmentMaxFiles"] = setting.Attachment.MaxFiles } // UploadAttachment response for uploading issue's attachment func UploadAttachment(ctx *context.Context) { - if !setting.AttachmentEnabled { + if !setting.Attachment.Enabled { ctx.Error(404, "attachment is not enabled") return } @@ -44,7 +45,7 @@ func UploadAttachment(ctx *context.Context) { buf = buf[:n] } - err = upload.VerifyAllowedContentType(buf, strings.Split(setting.AttachmentAllowedTypes, ",")) + err = upload.VerifyAllowedContentType(buf, strings.Split(setting.Attachment.AllowedTypes, ",")) if err != nil { ctx.Error(400, err.Error()) return diff --git a/routers/repo/issue.go b/routers/repo/issue.go index 2eabd6ab6c34f..d671f8de74ea7 100644 --- a/routers/repo/issue.go +++ b/routers/repo/issue.go @@ -692,7 +692,7 @@ func NewIssuePost(ctx *context.Context, form auth.CreateIssueForm) { return } - if setting.AttachmentEnabled { + if setting.Attachment.Enabled { attachments = form.Files } @@ -1633,7 +1633,7 @@ func NewComment(ctx *context.Context, form auth.CreateCommentForm) { } var attachments []string - if setting.AttachmentEnabled { + if setting.Attachment.Enabled { attachments = form.Files } diff --git a/routers/repo/pull.go b/routers/repo/pull.go index ed70ec13a8001..a19dbb5cb3cdb 100644 --- a/routers/repo/pull.go +++ b/routers/repo/pull.go @@ -911,7 +911,7 @@ func CompareAndPullRequestPost(ctx *context.Context, form auth.CreateIssueForm) return } - if setting.AttachmentEnabled { + if setting.Attachment.Enabled { attachments = form.Files } diff --git a/routers/repo/release.go b/routers/repo/release.go index 02fbcaccafdbd..c93c8f5d6126c 100644 --- a/routers/repo/release.go +++ b/routers/repo/release.go @@ -212,7 +212,7 @@ func NewReleasePost(ctx *context.Context, form auth.NewReleaseForm) { } var attachmentUUIDs []string - if setting.AttachmentEnabled { + if setting.Attachment.Enabled { attachmentUUIDs = form.Files } @@ -333,7 +333,7 @@ func EditReleasePost(ctx *context.Context, form auth.EditReleaseForm) { } var attachmentUUIDs []string - if setting.AttachmentEnabled { + if setting.Attachment.Enabled { attachmentUUIDs = form.Files } From 3b470201f4491102fc82862521ec74b1a959a90d Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 18 May 2020 00:59:41 +0800 Subject: [PATCH 07/59] Add documents --- cmd/migrate_storage.go | 28 +++++++++++-------- custom/conf/app.example.ini | 22 +++++++++++++-- .../doc/advanced/config-cheat-sheet.en-us.md | 10 ++++++- .../doc/advanced/config-cheat-sheet.zh-cn.md | 10 ++++++- 4 files changed, 54 insertions(+), 16 deletions(-) diff --git a/cmd/migrate_storage.go b/cmd/migrate_storage.go index 496f18e119191..4e75a018469db 100644 --- a/cmd/migrate_storage.go +++ b/cmd/migrate_storage.go @@ -42,39 +42,43 @@ var CmdMigrateStorage = cli.Command{ cli.StringFlag{ Name: "minio-endpoint", Value: "", - Usage: "New storage placement if store is local", + Usage: "New minio storage endpoint", }, cli.StringFlag{ Name: "minio-access-key-id", Value: "", - Usage: "New storage placement if store is local", + Usage: "New minio storage accessKeyID", }, cli.StringFlag{ - Name: "minio-scret-access-key", + Name: "minio-secret-access-key", Value: "", - Usage: "New storage placement if store is local", + Usage: "New minio storage secretAccessKey", }, cli.StringFlag{ Name: "minio-bucket", Value: "", - Usage: "New storage placement if store is local", + Usage: "New minio storage bucket", }, cli.StringFlag{ Name: "minio-location", Value: "", - Usage: "New storage placement if store is local", + Usage: "New minio storage location to create bucket", }, cli.StringFlag{ - Name: "minio-use-ssl", + Name: "minio-base-path", Value: "", - Usage: "New storage placement if store is local", + Usage: "New minio storage basepath on the bucket", + }, + cli.BoolFlag{ + Name: "minio-use-ssl", + Usage: "New minio storage SSL enabled", }, }, } func migrateAttachments(dstStorage storage.ObjectStorage) error { return models.IterateAttachment(func(attach *models.Attachment) error { - _, err := storage.Copy(dstStorage, attach.UUID, storage.Attachments, attach.RelativePath()) + _, err := storage.Copy(dstStorage, attach.RelativePath(), storage.Attachments, attach.RelativePath()) return err }) } @@ -106,7 +110,7 @@ func runMigrateStorage(ctx *cli.Context) error { var err error switch ctx.String("store") { case "local": - dstStorage, err = storage.NewLocalStorage(ctx.String("dst")) + dstStorage, err = storage.NewLocalStorage(ctx.String("path")) case "minio": dstStorage, err = storage.NewMinioStorage( ctx.String("minio-endpoint"), @@ -114,8 +118,8 @@ func runMigrateStorage(ctx *cli.Context) error { ctx.String("minio-secret-access-key"), ctx.String("minio-bucket"), ctx.String("minio-location"), - ctx.String("minio-basePath"), - ctx.Bool("minio-useSSL"), + ctx.String("minio-base-path"), + ctx.Bool("minio-use-ssl"), ) default: return fmt.Errorf("Unsupported attachments store type: %s", ctx.String("store")) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index a0aed626ed1a6..5ba6d328c3188 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -749,14 +749,32 @@ ENABLE_FEDERATED_AVATAR = false [attachment] ; Whether attachments are enabled. Defaults to `true` ENABLED = true -; Path for attachments. Defaults to `data/attachments` -PATH = data/attachments + ; One or more allowed types, e.g. "image/jpeg|image/png". Use "*/*" for all types. ALLOWED_TYPES = image/jpeg|image/png|application/zip|application/gzip ; Max size of each file. Defaults to 4MB MAX_SIZE = 4 ; Max number of files per upload. Defaults to 5 MAX_FILES = 5 +; Storage type for attachments, `local` for local disk or `minio` for s3 compitable +; object storage service, default is `local`. +STORE_TYPE = local +; Path for attachments. Defaults to `data/attachments` only available when STORE_TYPE is `local` +PATH = data/attachments +; Minio endpoint to connect only available when STORE_TYPE is `minio` +MINIO_ENDPOINT = localhost:9000 +; Minio accessKeyID to connect only available when STORE_TYPE is `minio` +MINIO_ACCESS_KEY_ID = +; Minio secretAccessKey to connect only available when STORE_TYPE is `minio` +MINIO_SECRET_ACCESS_KEY = +; Minio bucket to store the attachments only available when STORE_TYPE is `minio` +MINIO_BUCKET = gitea +; Minio location to create bucket only available when STORE_TYPE is `minio` +MINIO_LOCATION = us-east-1 +; Minio base path on the bucket only available when STORE_TYPE is `minio` +MINIO_BASE_PATH = attachments/ +; Minio enabled ssl only available when STORE_TYPE is `minio` +MINIO_USE_SSL = false [time] ; Specifies the format for fully outputted dates. Defaults to RFC1123 diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 39fc350e4f40a..e1abf80bb286e 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -470,11 +470,19 @@ set name for unique queues. Individual queues will default to ## Attachment (`attachment`) - `ENABLED`: **true**: Enable this to allow uploading attachments. -- `PATH`: **data/attachments**: Path to store attachments. - `ALLOWED_TYPES`: **see app.example.ini**: Allowed MIME types, e.g. `image/jpeg|image/png`. Use `*/*` for all types. - `MAX_SIZE`: **4**: Maximum size (MB). - `MAX_FILES`: **5**: Maximum number of attachments that can be uploaded at once. +- `STORE_TYPE`: **local**: Storage type for attachments, `local` for local disk or `minio` for s3 compitable object storage service, default is `local`. +- `PATH`: **data/attachments**: Path to store attachments only available when STORE_TYPE is `local` +- `MINIO_ENDPOINT`: **localhost:9000**: Minio endpoint to connect only available when STORE_TYPE is `minio` +- `MINIO_ACCESS_KEY_ID`: Minio accessKeyID to connect only available when STORE_TYPE is `minio` +- `MINIO_SECRET_ACCESS_KEY`: Minio secretAccessKey to connect only available when STORE_TYPE is `minio` +- `MINIO_BUCKET`: **gitea**: Minio bucket to store the attachments only available when STORE_TYPE is `minio` +- `MINIO_LOCATION`: **us-east-1**: Minio location to create bucket only available when STORE_TYPE is `minio` +- `MINIO_BASE_PATH`: **attachments/**: Minio base path on the bucket only available when STORE_TYPE is `minio` +- `MINIO_USE_SSL`: **false**: Minio enabled ssl only available when STORE_TYPE is `minio` ## Log (`log`) diff --git a/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md b/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md index 48cf0b4629d5c..dd3735e9c0916 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md +++ b/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md @@ -180,10 +180,18 @@ menu: ## Attachment (`attachment`) - `ENABLED`: 是否允许用户上传附件。 -- `PATH`: 附件存储路径 - `ALLOWED_TYPES`: 允许上传的附件类型。比如:`image/jpeg|image/png`,用 `*/*` 表示允许任何类型。 - `MAX_SIZE`: 附件最大限制,单位 MB,比如: `4`。 - `MAX_FILES`: 一次最多上传的附件数量,比如: `5`。 +- `STORE_TYPE`: **local**: 附件存储类型,`local` 将存储到本地文件夹, `minio` 将存储到 s3 兼容的对象存储服务中。 +- `PATH`: **data/attachments**: 附件存储路径,仅当 `STORE_TYPE` 为 `local` 时有效。 +- `MINIO_ENDPOINT`: **localhost:9000**: Minio 终端,仅当 `STORE_TYPE` 是 `minio` 时有效。 +- `MINIO_ACCESS_KEY_ID`: Minio accessKeyID ,仅当 `STORE_TYPE` 是 `minio` 时有效。 +- `MINIO_SECRET_ACCESS_KEY`: Minio secretAccessKey,仅当 `STORE_TYPE` 是 `minio` 时有效。 +- `MINIO_BUCKET`: **gitea**: Minio bucket to store the attachments,仅当 `STORE_TYPE` 是 `minio` 时有效。 +- `MINIO_LOCATION`: **us-east-1**: Minio location to create bucket,仅当 `STORE_TYPE` 是 `minio` 时有效。 +- `MINIO_BASE_PATH`: **attachments/**: Minio base path on the bucket,仅当 `STORE_TYPE` 是 `minio` 时有效。 +- `MINIO_USE_SSL`: **false**: Minio enabled ssl,仅当 `STORE_TYPE` 是 `minio` 时有效。 关于 `ALLOWED_TYPES`, 在 (*)unix 系统中可以使用`file -I ` 来快速获得对应的 `MIME type`。 From 31881521cc118f0bc2172c724d9b51c64834497c Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 18 May 2020 01:07:31 +0800 Subject: [PATCH 08/59] fix lint --- modules/storage/minio.go | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/storage/minio.go b/modules/storage/minio.go index 46bac876c7394..e93416bf7bd76 100644 --- a/modules/storage/minio.go +++ b/modules/storage/minio.go @@ -20,7 +20,6 @@ var ( type MinioStorage struct { client *minio.Client bucket string - location string basePath string } From c64f6029e5eb7b25af59e593fd861a8db66cb2bf Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 18 May 2020 01:27:53 +0800 Subject: [PATCH 09/59] Add test for minio store type on attachments --- .drone.yml | 8 ++++++++ integrations/sqlite.ini.tmpl | 10 ++++++++++ 2 files changed, 18 insertions(+) diff --git a/.drone.yml b/.drone.yml index fd32ad829cdc1..d6dcd5ca0c5d5 100644 --- a/.drone.yml +++ b/.drone.yml @@ -150,6 +150,14 @@ services: environment: discovery.type: single-node image: elasticsearch:7.5.0 + + - name: minio + image: minio/minio:RELEASE.2020-05-16T01-33-21Z + commands: + - minio server ./data + environment: + MINIO_ACCESS_KEY: 123456 + MINIO_SECRET_KEY: 123456 steps: - name: fetch-tags diff --git a/integrations/sqlite.ini.tmpl b/integrations/sqlite.ini.tmpl index e899328c81fe9..5bec06ee84aed 100644 --- a/integrations/sqlite.ini.tmpl +++ b/integrations/sqlite.ini.tmpl @@ -87,3 +87,13 @@ INTERNAL_TOKEN = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0OTI3OTU5ODN9.O [oauth2] JWT_SECRET = KZb_QLUd4fYVyxetjxC4eZkrBgWM2SndOOWDNtgUUko + +[attachment] +STORE_TYPE = minio +MINIO_ENDPOINT = localhost:9000 +MINIO_ACCESS_KEY_ID = 123456 +MINIO_SECRET_ACCESS_KEY = 123456 +MINIO_BUCKET = gitea +MINIO_LOCATION = us-east-1 +MINIO_BASE_PATH = attachments/ +MINIO_USE_SSL = false \ No newline at end of file From d600a207fde5b34fb5e9197258d7658e78da436f Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 18 May 2020 08:52:50 +0800 Subject: [PATCH 10/59] fix test --- models/unit_tests.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/models/unit_tests.go b/models/unit_tests.go index dca363ffacd8b..abeaa7ce75827 100644 --- a/models/unit_tests.go +++ b/models/unit_tests.go @@ -15,6 +15,7 @@ import ( "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/storage" "code.gitea.io/gitea/modules/util" "github.com/stretchr/testify/assert" @@ -67,6 +68,10 @@ func MainTest(m *testing.M, pathToGiteaRoot string) { fatalTestError("url.Parse: %v\n", err) } + if err = storage.Init(); err != nil { + fatalTestError("storage.Init: %v\n", err) + } + if err = util.RemoveAll(setting.RepoRootPath); err != nil { fatalTestError("util.RemoveAll: %v\n", err) } From ec36cce5a412eeb938bc4620c4a5b66f75788c16 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 18 May 2020 09:21:39 +0800 Subject: [PATCH 11/59] fix test --- models/unit_tests.go | 1 + 1 file changed, 1 insertion(+) diff --git a/models/unit_tests.go b/models/unit_tests.go index abeaa7ce75827..11b7708ffd874 100644 --- a/models/unit_tests.go +++ b/models/unit_tests.go @@ -68,6 +68,7 @@ func MainTest(m *testing.M, pathToGiteaRoot string) { fatalTestError("url.Parse: %v\n", err) } + setting.Attachment.Path = filepath.Join(setting.AppDataPath, "attachments") if err = storage.Init(); err != nil { fatalTestError("storage.Init: %v\n", err) } From 5390ce258247ea22c66fdd99ebe83487d04d8070 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 20 May 2020 15:06:25 +0800 Subject: [PATCH 12/59] Apply suggestions from code review Co-authored-by: guillep2k <18600385+guillep2k@users.noreply.github.com> --- cmd/migrate_storage.go | 18 +++++++++--------- custom/conf/app.example.ini | 2 +- .../doc/advanced/config-cheat-sheet.en-us.md | 2 +- models/attachment.go | 2 +- modules/storage/local.go | 4 ++-- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/cmd/migrate_storage.go b/cmd/migrate_storage.go index 4e75a018469db..4b17b7500b867 100644 --- a/cmd/migrate_storage.go +++ b/cmd/migrate_storage.go @@ -27,7 +27,7 @@ var CmdMigrateStorage = cli.Command{ cli.StringFlag{ Name: "type, t", Value: "", - Usage: "Files type to migrate, currently should be attachments", + Usage: "Kinds of files to migrate, currently only 'attachments' is supported", }, cli.StringFlag{ Name: "store, s", @@ -37,41 +37,41 @@ var CmdMigrateStorage = cli.Command{ cli.StringFlag{ Name: "path, p", Value: "", - Usage: "New storage placement if store is local", + Usage: "New storage placement if store is local (leave blank for default)", }, cli.StringFlag{ Name: "minio-endpoint", Value: "", - Usage: "New minio storage endpoint", + Usage: "Minio storage endpoint", }, cli.StringFlag{ Name: "minio-access-key-id", Value: "", - Usage: "New minio storage accessKeyID", + Usage: "Minio storage accessKeyID", }, cli.StringFlag{ Name: "minio-secret-access-key", Value: "", - Usage: "New minio storage secretAccessKey", + Usage: "Minio storage secretAccessKey", }, cli.StringFlag{ Name: "minio-bucket", Value: "", - Usage: "New minio storage bucket", + Usage: "Minio storage bucket", }, cli.StringFlag{ Name: "minio-location", Value: "", - Usage: "New minio storage location to create bucket", + Usage: "Minio storage location to create bucket", }, cli.StringFlag{ Name: "minio-base-path", Value: "", - Usage: "New minio storage basepath on the bucket", + Usage: "Minio storage basepath on the bucket", }, cli.BoolFlag{ Name: "minio-use-ssl", - Usage: "New minio storage SSL enabled", + Usage: "Enable SSL for minio", }, }, } diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 5ba6d328c3188..38b501f339df8 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -756,7 +756,7 @@ ALLOWED_TYPES = image/jpeg|image/png|application/zip|application/gzip MAX_SIZE = 4 ; Max number of files per upload. Defaults to 5 MAX_FILES = 5 -; Storage type for attachments, `local` for local disk or `minio` for s3 compitable +; Storage type for attachments, `local` for local disk or `minio` for s3 compatible ; object storage service, default is `local`. STORE_TYPE = local ; Path for attachments. Defaults to `data/attachments` only available when STORE_TYPE is `local` diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index e1abf80bb286e..2556fcd091d63 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -474,7 +474,7 @@ set name for unique queues. Individual queues will default to Use `*/*` for all types. - `MAX_SIZE`: **4**: Maximum size (MB). - `MAX_FILES`: **5**: Maximum number of attachments that can be uploaded at once. -- `STORE_TYPE`: **local**: Storage type for attachments, `local` for local disk or `minio` for s3 compitable object storage service, default is `local`. +- `STORE_TYPE`: **local**: Storage type for attachments, `local` for local disk or `minio` for s3 compatible object storage service, default is `local`. - `PATH`: **data/attachments**: Path to store attachments only available when STORE_TYPE is `local` - `MINIO_ENDPOINT`: **localhost:9000**: Minio endpoint to connect only available when STORE_TYPE is `minio` - `MINIO_ACCESS_KEY_ID`: Minio accessKeyID to connect only available when STORE_TYPE is `minio` diff --git a/models/attachment.go b/models/attachment.go index 2da4223fccd02..54cd562443e00 100644 --- a/models/attachment.go +++ b/models/attachment.go @@ -272,7 +272,7 @@ func DeleteAttachmentsByRelease(releaseID int64) error { return err } -// IterateAttachment iterates attachments +// IterateAttachment iterates attachments; it should not be used when Gitea is servicing users. func IterateAttachment(f func(attach *Attachment) error) error { var start int const batchSize = 100 diff --git a/modules/storage/local.go b/modules/storage/local.go index 7a5f00e63685a..c570babec7a86 100644 --- a/modules/storage/local.go +++ b/modules/storage/local.go @@ -30,7 +30,7 @@ func NewLocalStorage(bucket string) (*LocalStorage, error) { }, nil } -// Open open a file +// Open a file func (l *LocalStorage) Open(path string) (io.ReadCloser, error) { f, err := os.Open(filepath.Join(l.dir, path)) if err != nil { @@ -39,7 +39,7 @@ func (l *LocalStorage) Open(path string) (io.ReadCloser, error) { return f, nil } -// Save save a file +// Save a file func (l *LocalStorage) Save(path string, r io.Reader) (int64, error) { p := filepath.Join(l.dir, path) if err := os.MkdirAll(filepath.Dir(p), os.ModePerm); err != nil { From 3c56f5d0bf3fc19b49658ed8851edc1a8a606dfd Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 20 May 2020 15:19:42 +0800 Subject: [PATCH 13/59] Add warning when storage migrated successfully --- cmd/migrate_storage.go | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/cmd/migrate_storage.go b/cmd/migrate_storage.go index 4b17b7500b867..e53ddeb32124a 100644 --- a/cmd/migrate_storage.go +++ b/cmd/migrate_storage.go @@ -110,7 +110,12 @@ func runMigrateStorage(ctx *cli.Context) error { var err error switch ctx.String("store") { case "local": - dstStorage, err = storage.NewLocalStorage(ctx.String("path")) + p := ctx.String("path") + if p == "" { + log.Fatal("Path must be given when store is loal") + return nil + } + dstStorage, err = storage.NewLocalStorage(p) case "minio": dstStorage, err = storage.NewMinioStorage( ctx.String("minio-endpoint"), @@ -128,7 +133,13 @@ func runMigrateStorage(ctx *cli.Context) error { if err != nil { return err } - return migrateAttachments(dstStorage) + if err := migrateAttachments(dstStorage); err != nil { + return err + } + + log.Warn("All files have been copied to the new placement but old files are still on the orignial placement.") + + return nil } return nil From e8344c852c447bb7db831127993b72c3f4e1e35b Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 3 Jun 2020 00:12:50 +0800 Subject: [PATCH 14/59] Fix drone --- .drone.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.drone.yml b/.drone.yml index d6dcd5ca0c5d5..0079fc63116a9 100644 --- a/.drone.yml +++ b/.drone.yml @@ -150,14 +150,6 @@ services: environment: discovery.type: single-node image: elasticsearch:7.5.0 - - - name: minio - image: minio/minio:RELEASE.2020-05-16T01-33-21Z - commands: - - minio server ./data - environment: - MINIO_ACCESS_KEY: 123456 - MINIO_SECRET_KEY: 123456 steps: - name: fetch-tags @@ -304,6 +296,14 @@ services: pull: default image: gitea/test-openldap:latest + - name: minio + image: minio/minio:RELEASE.2020-05-16T01-33-21Z + commands: + - minio server ./data + environment: + MINIO_ACCESS_KEY: 123456 + MINIO_SECRET_KEY: 123456 + steps: - name: fetch-tags pull: default From bcede71087efba76d70fe4bb37a1886ba17441b0 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 8 Jun 2020 20:24:14 +0800 Subject: [PATCH 15/59] fix test --- integrations/sqlite.ini.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integrations/sqlite.ini.tmpl b/integrations/sqlite.ini.tmpl index 5bec06ee84aed..db171c2eecef6 100644 --- a/integrations/sqlite.ini.tmpl +++ b/integrations/sqlite.ini.tmpl @@ -90,7 +90,7 @@ JWT_SECRET = KZb_QLUd4fYVyxetjxC4eZkrBgWM2SndOOWDNtgUUko [attachment] STORE_TYPE = minio -MINIO_ENDPOINT = localhost:9000 +MINIO_ENDPOINT = minio:9000 MINIO_ACCESS_KEY_ID = 123456 MINIO_SECRET_ACCESS_KEY = 123456 MINIO_BUCKET = gitea From 3efe2323e33138bc9e741fe6e9bf203ea8486dfd Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 18 Jun 2020 10:00:16 +0800 Subject: [PATCH 16/59] rebase --- go.mod | 2 +- go.sum | 44 +- vendor/github.com/go-ini/ini/struct.go | 17 +- vendor/golang.org/x/net/publicsuffix/table.go | 19534 ++++++++-------- vendor/modules.txt | 2 +- 5 files changed, 9834 insertions(+), 9765 deletions(-) diff --git a/go.mod b/go.mod index 6308dafc05067..ed755f07d4e23 100644 --- a/go.mod +++ b/go.mod @@ -41,7 +41,7 @@ require ( github.com/go-enry/go-enry/v2 v2.5.2 github.com/go-git/go-billy/v5 v5.0.0 github.com/go-git/go-git/v5 v5.1.0 - github.com/go-ini/ini v1.56.0 // indirect + github.com/go-ini/ini v1.57.0 // indirect github.com/go-openapi/jsonreference v0.19.3 // indirect github.com/go-redis/redis v6.15.2+incompatible github.com/go-sql-driver/mysql v1.5.0 diff --git a/go.sum b/go.sum index 0571df29bcf42..33323ade3a459 100644 --- a/go.sum +++ b/go.sum @@ -235,15 +235,10 @@ github.com/go-git/go-billy/v5 v5.0.0 h1:7NQHvd9FVid8VL4qVUMm8XifBK+2xCoZ2lSk0agR github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= github.com/go-git/go-git-fixtures/v4 v4.0.1 h1:q+IFMfLx200Q3scvt2hN79JsEzy4AmBTp/pqnefH+Bc= github.com/go-git/go-git-fixtures/v4 v4.0.1/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw= -<<<<<<< HEAD github.com/go-git/go-git/v5 v5.1.0 h1:HxJn9g/E7eYvKW3Fm7Jt4ee8LXfPOm/H1cdDu8vEssk= github.com/go-git/go-git/v5 v5.1.0/go.mod h1:ZKfuPUoY1ZqIG4QG9BDBh3G4gLM5zvPuSJAozQrZuyM= -======= -github.com/go-git/go-git/v5 v5.0.0 h1:k5RWPm4iJwYtfWoxIJy4wJX9ON7ihPeZZYC1fLYDnpg= -github.com/go-git/go-git/v5 v5.0.0/go.mod h1:oYD8y9kWsGINPFJoLdaScGCN6dlKg23blmClfZwtUVA= -github.com/go-ini/ini v1.56.0 h1:6HjxSjqdmgnujDPhlzR4a44lxK3w03WPN8te0SoUSeM= -github.com/go-ini/ini v1.56.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= ->>>>>>> Add a storage layer for attachments +github.com/go-ini/ini v1.57.0 h1:Qwzj3wZQW+Plax5Ntj+GYe07DfGj1OH+aL1nMTMaNow= +github.com/go-ini/ini v1.57.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= @@ -341,13 +336,11 @@ github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0 h1:oOuy+ugB+P/kBdUnG5QaMXSIyJ1q38wWSojYCb3z5VQ= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1 h1:ZFgWrT+bLgsYPirOnRfKLYJLvssAegOj/hgyMFdJZe0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= @@ -358,7 +351,6 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -377,7 +369,6 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c h1:7lF+Vz0LqiRidnzC1Oq86fpX1q/iEv2KJdrCtttYjT4= github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99 h1:twflg0XRTjwKpxb/jFExr4HGq6on2dEOmnL6FV+fgPw= github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= @@ -408,7 +399,6 @@ github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVo github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= -github.com/hashicorp/go-retryablehttp v0.6.4 h1:BbgctKO892xEyOXnGiaAwIoSq1QZ/SS4AhjoAh9DnfY= github.com/hashicorp/go-retryablehttp v0.6.4/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-retryablehttp v0.6.6 h1:HJunrbHTDDbBb/ay4kxa1n+dLmttUlnP3V9oNE4hmsM= github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= @@ -498,7 +488,6 @@ github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4/go.mod h1:ghbZsc github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.9.2 h1:LfVyl+ZlLlLDeQ/d2AqfGIIH4qEDu0Ed2S5GyhCWIWY= github.com/klauspost/compress v1.9.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.10.2 h1:Znfn6hXZAHaLPNnlqUYRrBSReFHYybslgv4PTiyz6P0= github.com/klauspost/compress v1.10.2/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= @@ -514,7 +503,6 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= @@ -523,7 +511,6 @@ github.com/lafriks/xormstore v1.3.2/go.mod h1:mVNIwIa25QIr8rfR7YlVjrqN/apswHkVdt github.com/lestrrat-go/jwx v0.9.0/go.mod h1:iEoxlYfZjvoGpuWwxUz+eR5e6KTJGsaRcy/YNA/UnBk= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.7.0 h1:h93mCPfUSkaul3Ka/VG8uZdmW1uMHDGxzu0NWHuJmHY= @@ -565,7 +552,6 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54= github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/mattn/go-sqlite3 v1.11.0 h1:LDdKkqtYlom37fkvqs8rMPFKAMe8+SgjbwZ6ex1/A/Q= github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA= github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus= @@ -593,7 +579,6 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mrjones/oauth v0.0.0-20180629183705-f4e24b6d100c h1:3wkDRdxK92dF+c1ke2dtj7ZzemFWBHB9plnJOtlwdFA= github.com/mrjones/oauth v0.0.0-20180629183705-f4e24b6d100c/go.mod h1:skjdDftzkFALcuGzYSklqYd8gvat6F1gZJ4YPVbkZpM= -github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae h1:VeRdUYdCw49yizlSbMEn2SZ+gT+3IUKx8BqxyQdz+BY= github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg= github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM= github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw= @@ -634,7 +619,6 @@ github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -678,7 +662,6 @@ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6So github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= -github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= @@ -718,7 +701,6 @@ github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tL github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= -github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= @@ -729,7 +711,6 @@ github.com/steveyen/gtreap v0.1.0 h1:CjhzTa274PyJLJuMZwIzCO1PfC00oRa8d1Kc78bFXJM github.com/steveyen/gtreap v0.1.0/go.mod h1:kl/5J7XbrOmlIbYIXdRHDDE5QxHqpk0cmkT7Z4dM9/Y= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -743,7 +724,6 @@ github.com/tecbot/gorocksdb v0.0.0-20181010114359-8752a9433481 h1:HOxvxvnntLiPn1 github.com/tecbot/gorocksdb v0.0.0-20181010114359-8752a9433481/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8= github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= -github.com/tinylib/msgp v1.1.0 h1:9fQd+ICuRIu/ue4vxJZu6/LzxN0HwMds2nq/0cFvxHU= github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= github.com/tinylib/msgp v1.1.2 h1:gWmO7n0Ys2RBEb7GPYB9Ujq8Mk5p2U08lRnmMcGy6BQ= github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= @@ -756,7 +736,6 @@ github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGr github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ulikunitz/xz v0.5.6 h1:jGHAfXawEGZQ3blwU5wnWKQJvAraT7Ftq9EXjnXYgt8= github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= -github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e h1:GSGeB9EAKY2spCABz6xOX5DbxZEXolK+nBSvmsQwRjM= github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM= github.com/unknwon/com v1.0.1 h1:3d1LTxD+Lnf3soQiD4Cp/0BRB+Rsa/+RTvz8GMMzIXs= github.com/unknwon/com v1.0.1/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM= @@ -822,10 +801,8 @@ golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190907121410-71b5226ff739/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad h1:5E5raQxcv+6CZ11RrBYQe5WRbUIWpScjh0kvHZkZIrQ= golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 h1:xMPOj6Pz6UipU1wXLkrtqpHbR0AVFnyPEQq/wRWz9lM= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -840,7 +817,6 @@ golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTk golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee h1:WG0RUwxtNT4qqaXX3DPA8zHFNm/D9xaBpxzHt1WcA/E= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -871,7 +847,6 @@ golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4= @@ -880,7 +855,6 @@ golang.org/x/oauth2 v0.0.0-20180620175406-ef147856a6dd/go.mod h1:N/0e6XlmueqKjAG golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -918,15 +892,12 @@ golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190907184412-d223b2b6db03/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191010194322-b09406accb47 h1:/XfQ9z7ib8eEJX2hdgFTZJ/ntt0swNk5oYBziWeTCvY= golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM/fAoGlaiiHYiFYdm80= @@ -937,7 +908,6 @@ golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 h1:NusfzzA6yGQ+ua51ck7E3omNUX/JuqbFSaRGqU8CcLI= golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -960,7 +930,6 @@ golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200225230052-807dcd883420 h1:4RJNOV+2rLxMEfr6QIpC7GEv9MjD6ApGXTCLrNF9+eA= golang.org/x/tools v0.0.0-20200225230052-807dcd883420/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224 h1:azwY/v0y0K4mFHVsg5+UrTgchqALYWpqVo6vL5OmkmI= golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= @@ -969,7 +938,6 @@ golang.org/x/tools v0.0.0-20200814230902-9882f1d1823d/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -986,7 +954,6 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.2/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.4 h1:WiKh4+/eMB2HaY7QhCfW/R7MuRAoA8QMCSJA6jP5/fo= google.golang.org/appengine v1.6.4/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= @@ -1007,7 +974,6 @@ google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLY google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0 h1:qdOKuR/EIArgaWNjetjgTzgVTAZ+S/WXVrq9HW9zimw= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.22.0 h1:cJv5/xdbk1NnMPR1VP9+HU6gupuG9MLBoH1r6RHZ2MY= google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= @@ -1018,7 +984,6 @@ gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175 h1:nn6Zav2sOQHCFJHEspya8 gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1043,12 +1008,9 @@ gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -1062,13 +1024,11 @@ mvdan.cc/xurls/v2 v2.1.0/go.mod h1:5GrSd9rOnKOpZaji1OZLYL/yeAAtGDlo/cFe+8K5n8E= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251 h1:mUcz5b3FJbP5Cvdq7Khzn6J9OCUQJaBwgBkCR+MOwSs= strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251/go.mod h1:FJGmPh3vz9jSos1L/F91iAgnC/aejc0wIIrF2ZwJxdY= -xorm.io/builder v0.3.6 h1:ha28mQ2M+TFx96Hxo+iq6tQgnkC9IZkM6D8w9sKHHF8= xorm.io/builder v0.3.6/go.mod h1:LEFAPISnRzG+zxaxj2vPicRwz67BdhFreKg8yv8/TgU= xorm.io/builder v0.3.7 h1:2pETdKRK+2QG4mLX4oODHEhn5Z8j1m8sXa7jfu+/SZI= xorm.io/builder v0.3.7/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE= xorm.io/core v0.7.2 h1:mEO22A2Z7a3fPaZMk6gKL/jMD80iiyNwRrX5HOv3XLw= xorm.io/core v0.7.2/go.mod h1:jJfd0UAEzZ4t87nbQYtVjmqpIODugN6PD2D9E+dJvdM= -xorm.io/xorm v0.8.0 h1:iALxgJrX8O00f8Jk22GbZwPmxJNgssV5Mv4uc2HL9PM= xorm.io/xorm v0.8.0/go.mod h1:ZkJLEYLoVyg7amJK/5r779bHyzs2AU8f8VMiP6BM7uY= xorm.io/xorm v1.0.4-0.20200718080127-318102c9ff87 h1:vgc2F0wjD0cyrNrSKiIdWu123wuKkPQI84DZUKvJ6ns= xorm.io/xorm v1.0.4-0.20200718080127-318102c9ff87/go.mod h1:uF9EtbhODq5kNWxMbnBEj8hRRZnlcNSz2t2N7HW/+A4= diff --git a/vendor/github.com/go-ini/ini/struct.go b/vendor/github.com/go-ini/ini/struct.go index 1df54719041a4..9be40a9200681 100644 --- a/vendor/github.com/go-ini/ini/struct.go +++ b/vendor/github.com/go-ini/ini/struct.go @@ -278,7 +278,9 @@ func parseTagOptions(tag string) (rawName string, omitEmpty bool, allowShadow bo return rawName, omitEmpty, allowShadow, allowNonUnique } -func (s *Section) mapToField(val reflect.Value, isStrict bool) error { +// mapToField maps the given value to the matching field of the given section. +// The sectionIndex is the index (if non unique sections are enabled) to which the value should be added. +func (s *Section) mapToField(val reflect.Value, isStrict bool, sectionIndex int) error { if val.Kind() == reflect.Ptr { val = val.Elem() } @@ -307,13 +309,16 @@ func (s *Section) mapToField(val reflect.Value, isStrict bool) error { } if isAnonymous || isStruct || isStructPtr { - if sec, err := s.f.GetSection(fieldName); err == nil { + if secs, err := s.f.SectionsByName(fieldName); err == nil { + if len(secs) <= sectionIndex { + return fmt.Errorf("there are not enough sections (%d <= %d) for the field %q", len(secs), sectionIndex, fieldName) + } // Only set the field to non-nil struct value if we have a section for it. // Otherwise, we end up with a non-nil struct ptr even though there is no data. if isStructPtr && field.IsNil() { field.Set(reflect.New(tpField.Type.Elem())) } - if err = sec.mapToField(field, isStrict); err != nil { + if err = secs[sectionIndex].mapToField(field, isStrict, sectionIndex); err != nil { return fmt.Errorf("map to field %q: %v", fieldName, err) } continue @@ -350,9 +355,9 @@ func (s *Section) mapToSlice(secName string, val reflect.Value, isStrict bool) ( } typ := val.Type().Elem() - for _, sec := range secs { + for i, sec := range secs { elem := reflect.New(typ) - if err = sec.mapToField(elem, isStrict); err != nil { + if err = sec.mapToField(elem, isStrict, i); err != nil { return reflect.Value{}, fmt.Errorf("map to field from section %q: %v", secName, err) } @@ -382,7 +387,7 @@ func (s *Section) mapTo(v interface{}, isStrict bool) error { return nil } - return s.mapToField(val, isStrict) + return s.mapToField(val, isStrict, 0) } // MapTo maps section to given struct. diff --git a/vendor/golang.org/x/net/publicsuffix/table.go b/vendor/golang.org/x/net/publicsuffix/table.go index 369e44656ad73..8e1c9d3dd86f4 100644 --- a/vendor/golang.org/x/net/publicsuffix/table.go +++ b/vendor/golang.org/x/net/publicsuffix/table.go @@ -2,7 +2,7 @@ package publicsuffix -const version = "publicsuffix.org's public_suffix_list.dat, git revision 7922d7c20e246552be418e8f72e577899fd30d99 (2020-02-18T23:18:19Z)" +const version = "publicsuffix.org's public_suffix_list.dat, git revision dbe9da0a8abeab1b6257c57668d1ecb584189951 (2020-05-27T00:50:31Z)" const ( nodesBitsChildren = 10 @@ -23,488 +23,490 @@ const ( ) // numTLD is the number of top level domains. -const numTLD = 1528 +const numTLD = 1525 // Text is the combined text of all labels. const text = "9guacuiababia-goracleaningroks-theatree12hpalermomahachijoinvill" + - "eksvik12ix4432-balsfjordd-dnsiskinkyotobetsulikes-piedmonticello" + - "dingen4tatarantours3-ap-south-16-b-dataiji234lima-cityeatselinog" + - "radult3l3p0rtashkentatamotors3-ap-northeast-2038blackfridayuu2-l" + - "ocalhostoregontrailroadnparachutingleezebloombergbauernirasakind" + - "igenaklodzkochikushinonsenergyuzawabloxcms3-website-us-west-1blu" + - "edagestangemologicallimoliseminebmoattachments3-website-us-west-" + - "2bms5ybmweddinglitchattanooganordlandrangedalinkyard-cloudyclust" + - "erbnrwedeploybomloabathsbchernihivgubsakyotanabellunord-aurdalph" + - "a-myqnapcloudaccesscambridgestoneuesalangenishiazaindustriabondr" + - "ay-dnsupdaternopilawatchesalondonetskaruizawabonnishigohtawaramo" + - "toineppueblockbustermezparaglidingliwicebookinghostfoldnavybooml" + - "air-traffic-controlleyboschaefflerdalivornomutashinaindustrieste" + - "amfamberkeleybostikarumaifarmsteadrayddnsfreebox-osascoli-piceno" + - "rdre-landraydnsaltdalombardynaliaskimitsubatamibudejjuegoshikiho" + - "kumakogenebakkeshibechambagriculturennebugattiffanynysadoes-itve" + - "destrandrivefsnillfjordrobaknoluoktachikawakembuchikumagayagawak" + - "kanaibetsubamericanfamilydsclouderackmazerbaijan-mayen-rootaribe" + - "iraogashimadachicagoboatsaludrudupontariobranconakamuratajirivne" + - "bostonakijinsekikogentappsselfiparisor-fronishiharabotanicalgard" + - "enishiizunazukinfinitintuitjomeloyalistoragebotanicgardenishikat" + - "aketomisatomobellevuelosangelesjabbottjxfinitybotanybouncemerckm" + - "sdnipropetrovskjervoyageorgeorgiabounty-fullensakerrypropertiesa" + - "lvadordalibabalestrandabergamo-siemensncfdurbanamexnethnologybou" + - "tiquebechernivtsiciliabozen-sudtirolomzaporizhzhegurinuyamashina" + - "tsukigatakasakitaurayasudabozen-suedtirolondrinamsskoganeinvestm" + - "entsalzburglobalashovhachinohedmarkasaokamiminersamegawabplacedo" + - "gawarabikomaezakirunorddalorenskogloboavistanbulsan-sudtiroloten" + - "kawabrandywinevalleybrasiliabrindisibenikimobetsuitainaioiraseba" + - "stopologyeongnamegawafflecellclaimsamnangerbristoloseyouriparlia" + - "mentkmaxxjavald-aostarnberglogowegroweibolognagareyamakeupowiath" + - "letajimabaridagawakuyabukikonaikawachinaganoharamcoachampionship" + - "hoptobishimadridvagsoyerbritishcolumbialowiezaganishikatsuragit-" + - "reposampalacebroadcastleclerchernovtsymantechnologybroadwaybroke" + - "-itksatxn--0trq7p7nnishikawazukamisunagawabrokerbronnoysundurham" + - "burgloppenzaolbia-tempio-olbiatempioolbialystokkepnogatagajoboji" + - "nzais-a-candidatebrothermesaverdealstahaugesunderseaportsinfolld" + - "alottebrowsersafetymarketsamsclubartoweirbrumunddalottokonamegat" + - "akayamashikokuchuobrunelasticbeanstalkashibatakatoris-a-catererb" + - "russelsamsunglugmbhartipscbgminakamichiharabruxellesandnessjoeni" + - "shimerabryansklepparmatta-varjjatmparochernigovernmentoyosatoyok" + - "awabrynewjerseybuskerudinewmexicoalouvreitoyotaparsandoybuzentsu" + - "jiiebuzzwellbeingzonebwfarsundweberbzhitomirumalatvuopmicrolight" + - "ingmodellingmxn--11b4c3dynathomebuiltwithdarkashiharabzzcolumbus" + - "heycommunecommunity-prochowicecomoarekecomparemarkerryhotelsanta" + - "mariakecompute-1computerhistoryofscience-fictioncomsecuritytacti" + - "csantoandreamhostersanukis-a-cubicle-slavellinodearthachiojiyaho" + - "oguycondoshichinohealth-carereforminamidaitomanchesterconference" + - "constructionconsuladonnagatorodoyconsultanthropologyconsultingro" + - "ngausdalukowhalingrossetouchihayaakasakawaharacontactraniandriab" + - "arlettatraniandriacontagematsubaracontemporaryarteducationalchik" + - "ugodontexistmein-iservebeercontractorskenconventureshinodebalanc" + - "ertificationcookingchannelsdvrdnsfor-better-thanawassamukawatari" + - "ghtathomeftpartycooluroycooperativano-frankivskolegallocus-3cope" + - "nhagencyclopedichitosetogakushimotoganewyorkshirecifedexhibition" + - "ishinoomotegocorsicafederationcorvettemp-dnsaobernardocosenzakop" + - "anecosidnshome-webserverdalutskasuyameinforumzcostumedicinaharim" + - "alopolskanlandyndns-office-on-the-webhareidsbergentingroundhandl" + - "ingroznycouchpotatofriesaogoncarriercounciluxurycouponsaotomelda" + - "luzerncq-acranbrookuwanalyticsapporocrdyndns-picsardegnaroycredi" + - "tcardyndns-remotewdyndns-serverisigncreditunioncremonashgabadadd" + - "jaguarqcxn--12c1fe0bradescorporationrendercrewhoswhokksundyndns-" + - "webhopencraftranoycricketrzyncrimeast-kazakhstanangercrotonecrow" + - "nipasadenarashinocrsvpassagensardiniacruisesarlvivanovoldacrypto" + - "nomichigangwoncuisinellajollamericanexpressexyculturalcentertain" + - "mentransportecuneocupcakecuritibaghdadyndns-wikirkenesarpsborgrp" + - "assenger-associationcymrussiacyonabaruminamiechizencyouthruherec" + - "ipescaravantaarpatriaferrerotikagoshimalvikaszubyfetsundyndns1fg" + - "uidegreefhvalerfidoomdnstracefieldynnsarufutsunomiyawakasaikaita" + - "koelnfigueresinstaginguitarsauheradynservebbsasayamayfirstockhol" + - "mestrandyndns-workshopitsitexaskoyabearalvahkijobservableusercon" + - "tentransurlfilateliafilegear-audnedalnfilegear-deatnulminamiiser" + - "niafilegear-gbizfilegear-iefilegear-jpmorganfilegear-sgujohanama" + - "kinoharafilminamiizukamiokameokameyamatotakadafinalfinancefinear" + - "tsavannahgafinlandynufcfanfinnoyfirebaseapplinzis-a-doctorayfire" + - "nzefirestonefirmdalegoldpoint2thisamitsukefishingolffansaves-the" + - "-whalessandria-trani-barletta-andriatranibarlettaandriafitjarvod" + - "kafjordynv6fitnessettlementravelersinsurancefjalerflesbergulenfl" + - "ickragerogersavonarusawaflightsaxoflirfloginlinefloraflorenceflo" + - "ridattorelayfloripaderbornfloristanohatakaharulvikatowicefloroku" + - "nohealthcareerschoenbrunnflowerschokokekschokoladenfltrdynvpnplu" + - "s-4flynnhosting-clusterflynnhubarcelonagawalesundgcagliaricoharu" + - "ovataxihuanflfanfshostrowwlkpmgjerdrumemsettsupportcp4fndyroyrvi" + - "kingruefor-ourfor-somedizinhistorischescholarshipschoolschulefor" + - "-theaterforexrothachirogatakamoriokakudamatsueforgotdnschwarzgwa" + - "ngjuniperforli-cesena-forlicesenaforlikescandyn53forsaleikangerf" + - "orsandasuologoipaviancargodaddyn-o-saurlandeschweizfortalfortmis" + - "soulancasterfortworthadanorthwesternmutualfosnesciencecenterscie" + - "ncehistoryfotaruis-a-financialadvisor-aurdalfoxfordebianfozorafr" + - "edrikstadtvscientistordalfreeddnsgeekgalaxyfreedesktopocznore-og" + - "-uvdalfreemasonryfreesitextileirfjordfreetlscjohnsonfreiburgunma" + - "nxn--12co0c3b4evalleaostavangerfreightrentin-sud-tirolfreseniusc" + - "ountryestateofdelawareggio-calabriafribourguovdageaidnunusualper" + - "sonfriuli-v-giuliafriuli-ve-giuliafriuli-vegiuliafriuli-venezia-" + - "giuliafriuli-veneziagiuliafriuli-vgiuliafriuliv-giuliafriulive-g" + - "iuliafriulivegiuliafriulivenezia-giuliafriuliveneziagiuliafriuli" + - "vgiuliafrlfroganscotlandfrognfrolandfrom-akrehamnfrom-alfrom-arf" + - "rom-azimutheworkpccwiiheyakagefrom-capebretonamicrosoftbankatsus" + - "hikabeeldengeluidfrom-codyn-vpndnscrapper-sitefrom-ctrentin-sudt" + - "irolfrom-dchocolatelevisionishinoshimatsushigefrom-dedyn-berlinc" + - "olnfrom-flanderscrappingushikamifuranorth-kazakhstanfrom-gaulard" + - "alfrom-hichisochildrensgardenfrom-iafrom-idfrom-ilfrom-in-brbarc" + - "laycards3-sa-east-1from-kscrysechofunatoriginstitutemasekashiwaz" + - "akiyosatokamachintaifun-dnsdojolsterfrom-kyowariasahikawawildlif" + - "edorainfracloudfrontdoorfrom-lanciafrom-mamurogawafrom-mdfrom-me" + - "eresistancefrom-mifunefrom-mnfrom-modalenfrom-mserveirchonanbuls" + - "an-suedtirolowiczest-le-patronishiokoppegardyndns-at-homedepoten" + - "zamamidsundyndns-at-workisboringrimstadyndns-blogdnsangofrom-mtn" + - "from-nctulangevagrigentomologyeonggiehtavuoatnadexeterfrom-ndfro" + - "m-nefrom-nh-serveblogsiteleafamilycompanyminamimakis-a-geekatsuy" + - "amarugame-hostrowiechoseiroumuenchenishitosashimizunaminamibosog" + - "ndalpusercontentoyotsukaidofrom-njaworznoticiasnesoddenmarkhange" + - "lskjakdnepropetrovskiervaapsteiermarkaufenfrom-nminamiminowafrom" + - "-nvalled-aostavernfrom-nyfrom-ohkurafrom-oketogurafrom-orfrom-pa" + - "dovaksdalfrom-pratohmandalfrom-ris-a-greenfrom-schmidtre-gauldal" + - "from-sdfrom-tnfrom-txn--1ck2e1barclays3-us-east-2from-utazuerich" + - "ardlillehammerfeste-ipfizerfrom-val-daostavalleyfrom-vtrentin-su" + - "ed-tirolfrom-wafrom-wielunnerfrom-wvalledaostaobaomoriguchiharah" + - "kkeravjuedischesapeakebayernunzenfrom-wyfrosinonefrostalowa-wola" + - "wafroyahikobeardubaiduckdnserveminecraftrentin-suedtirolfstcgrou" + - "pgfoggiafujiiderafujikawaguchikonefujiminokamoenairguardiannakad" + - "omarineat-urlfujinomiyadavvenjargap-northeast-3fujiokayamangonoh" + - "ejis-a-guruslivinghistoryfujisatoshonairlinebraskauniversitychya" + - "ttorneyagawakayamagazinedre-eikerfujisawafujishiroishidakabirato" + - "ridefenseljordfujitsurugashimangyshlakasamatsudovre-eikerfujixer" + - "oxn--1ctwolominamatargivestbytemarkautokeinotteroyfujiyoshidavve" + - "siidatsunanjoburgwiddleitungsenfukayabeatservemp3fukuchiyamadaza" + - "ifudaigojomedio-campidano-mediocampidanomediofukudominichoshibuy" + - "achiyodatingripefukuis-a-hard-workerservep2pharmacienservepicser" + - "vequakefukumitsubishigakisarazurecontainerdpolicefukuokazakishiw" + - "adafukuroishikarikaturindalfukusakisofukushimaniwakuratefukuyama" + - "gatakahatakaishimogosenfunabashiriuchinadafunagatakamatsukawafun" + - "ahashikamiamakusatsumasendaisennangooglecodespotrentino-a-adigef" + - "undaciofuoiskujukuriyamannorfolkebibleirvikazoologyfuosskoczowil" + - "liamhillfurnitureggio-emilia-romagnakasatsunairportland-4-salern" + - "oboribetsuckservesarcasmatartanddesignfurubirafurudonostiaafuruk" + - "awairtelebitballooningxn--1lqs03nfusodegaurafussagamiharafutabay" + - "amaguchinomigawafutboldlygoingnowhere-for-morenakatombetsumitaka" + - "giizefuttsurugimperiafuturecmservicesevastopolefuturehostingfutu" + - "remailingfvgfylkesbiblackbaudcdn77-securebungoonord-odalwaysdata" + - "baseballangenkainanaejrietisalatinabenonicbcn-north-1fyresdalhan" + - "goutsystemscloudhannanmokuizumodenakayamapartmentsewinbarefootba" + - "llfinanzgoraustrheimatunduhrennesoyokozebinagisoccertmgretakaham" + - "alselvendrellaziobiramusementdllpages3-ap-southeast-2hannosegawa" + - "hanyuzenhapmirharstadharvestcelebrationhasamarburghasaminami-alp" + - "sharis-a-lawyerhashbanghasudahasura-appharmacysharphdfcbankddiel" + - "ddanuorrittogliattireshawaiijimaritimoduminamioguni5hasvikfhappo" + - "usrcfastly-terrariuminamifuranohatogayaitakanezawahatoyamazakita" + - "kamiizumisanofidelityhatsukaichikaiseis-a-liberalhattfjelldalhay" + - "ashimamotobungotakadancehazuminobusells-for-ustkannamilanotogawa" + - "helsinkitakatakaokalmykiahembygdsforbundhemneshellaspeziahemseda" + - "lhepforgeherokussldheroyhgtvallee-aosteroyhigashiagatsumagoiania" + - "higashichichibunkyonanaoshimageandsoundandvisionthewifiatmallorc" + - "adaqueshimojis-a-libertarianhigashihiroshimanehigashiizumozakita" + - "kyushuaiahigashikagawahigashikagurasoedahigashikawakitaaikitamih" + - "amadahigashikurumeetnedalhigashimatsushimarcheapigeelvinckhakass" + - "iahigashimatsuyamakitaakitadaitoigawahigashimurayamamotorcyclesh" + - "imokawahigashinarusells-itrentino-alto-adigehigashinehigashiomih" + - "achimanagementrentino-altoadigehigashiosakasayamanakakogawahigas" + - "hishirakawamatakarazukaluganskygearapphiladelphiaareadmyblogspot" + - "rentino-s-tirolhigashisumiyoshikawaminamiaikitamotosumy-gatewayh" + - "igashitsunoshiroomurahigashiurausukitanakagusukumodernhigashiyam" + - "atokoriyamanashifteditchyouriphilatelyhigashiyodogawahigashiyosh" + - "inogaris-a-linux-useranishiaritabashijonawatehiraizumisatohnosho" + - "ooshikamaishimodatehirakatashinagawahiranairtrafficplexus-1hirar" + - "ahiratsukagawahirayaizuwakamatsubushikusakadogawahistorichousesh" + - "imokitayamahitachiomiyagildeskaliszhitachiotagoppdalhitraeumtger" + - "adelmenhorstalbanshimonitayanagithubusercontentrentino-stirolhja" + - "rtdalhjelmelandholeckobierzyceholidayhomeiphilipsyno-dshimonosek" + - "ikawahomelinkitoolsztynsettlershimosuwalkis-a-llamarriottrentino" + - "-sud-tirolhomelinuxn--1lqs71dhomeofficehomesecuritymacaparecidah" + - "omesecuritypchoyodobashichikashukujitawaravennagasukehomesenseer" + - "inghomeunixn--1qqw23ahondahongotembaixadahonjyoitakasagotpantheo" + - "nsitehornindalhorsellsyourhomegoodshimotsukehorteneis-a-musician" + - "hospitalhoteleshimotsumahotmailhoyangerhoylandetroitskypehumanit" + - "ieshinichinanhurdalhurumajis-a-nascarfanhyllestadhyogoris-a-nurs" + - "embokukitchenhyugawarahyundaiwafuneis-very-sweetpepperis-with-th" + - "ebandoisleofmanaustdaljewelryjewishartgalleryjfkharkovalleedaost" + - "ejgorajlljmphotographysiojnjcphonefosshintomikasaharajoyentrenti" + - "noa-adigejoyokaichibalatinogiftshiojirishirifujiedajpnjprshioyan" + - "aizujurkoseis-a-personaltrainerkosherbrookegawakoshimizumakizuno" + - "kunimimatakatsukiyosemitekoshunantankhmelnitskiyamarumorimachida" + - "kosugekotohiradomainsurehabmerkotourakouhokutamakis-a-photograph" + - "erokuapphoenixn--2m4a15ekounosupplieshirakofuefukihaboromskogkou" + - "yamarylhurstjordalshalsenkouzushimasfjordenkozagawakozakis-a-pla" + - "yerkozowindmillkpnkppspdnshiranukamitsuekrasnikahokutokashikis-a" + - "-republicancerresearchaeologicaliforniakrasnodarkredstonekristia" + - "nsandcatshiraois-a-rockstarachowicekristiansundkrodsheradkroksta" + - "delvaldaostarostwodzislawindowskrakowinnershiraokamogawakryminam" + - "isanrikubetsurfastpanelblagrarchaeologyeongbuk0emmafann-arboretu" + - "mbriamallamaceiobbcg120001wwwebredirectmembers3-ap-northeast-133" + - "7kumatorinokumejimashikis-a-socialistdlibestadkumenantokigawakun" + - "isakis-a-soxfankunitachiarailwaykunitomigusukumamotoyamashikekun" + - "neppubtlshiratakahagitlaborkunstsammlungkunstunddesignkuokgroupi" + - "lotshishikuis-a-studentalkureisenkurgankurobelaudibleasingleshis" + - "ognekurogiminamiashigarakuroisoftwarendalenugkuromatsunais-a-tea" + - "cherkassyncloudkurotakikawasakis-a-techietis-a-painteractivegask" + - "vollkushirogawakustanais-a-therapistoiakusupplykutchanelkutnokuz" + - "umakis-an-accountantshinjournalismailillesandefjordkvafjordkvals" + - "undkvamlidlugolekadenagahamaroygardendoftheinternetlifyis-an-act" + - "orkvanangenkvinesdalkvinnheradkviteseidskogkvitsoykwpspectrumina" + - "mitanekzmissileluxembourgmisugitokorozawamitourismolanxesshisuif" + - "uettertdasnetzmitoyoakemiuramiyazurewebsiteshikagamiishibukawami" + - "yotamanomjondalenmlbfanmonstermontrealestatefarmequipmentrentino" + - "aadigemonza-brianzapposhitaramamonza-e-della-brianzaptokuyamatsu" + - "maebashikshacknetrentinoalto-adigemonzabrianzaramonzaebrianzamon" + - "zaedellabrianzamoonscalevangermordoviamoriyamatsumotofukemoriyos" + - "himinamiawajikis-an-engineeringmormonmouthaebaruericssongdalenvi" + - "knakatsugawamoroyamatsunomortgagemoscowioshizukuishimofusaitamat" + - "sukuris-an-entertainermoseushistorymosjoenmoskeneshizuokanagawam" + - "osshoppingmosvikhplaystationmoteginowaniihamatamakawajimansionsh" + - "oujis-bytomaritimekeepingmoviemovimientokyotangovtrentinoaltoadi" + - "gemozilla-iotrentinos-tirolmtranbymuenstermuginozawaonsenmuikami" + - "satokaizukamikitayamatsuris-certifieducatorahimeshimamateramobar" + - "amukodairamulhouseoullensvanguardmunakatanemuncienciamuosattemup" + - "imientakinouemurmansklabudhabikinokawabarthadselectrentino-aadig" + - "emurotorcraftrentinostirolmusashimurayamatsusakahoginankokubunji" + - "s-foundationmusashinoharamuseetrentinosud-tirolmuseumverenigingm" + - "usicarbonia-iglesias-carboniaiglesiascarboniamutsuzawamy-vigorge" + - "my-wanggouvichromedicaltanissettairamyactivedirectorymyasustor-e" + - "lvdalmycdn77-sslattuminamiuonumassa-carrara-massacarraramassabus" + - "inessebyklecznagasakinderoymydattolocalhistorymyddnskingmydissen" + - "trentinosudtirolmydobisshikis-gonemydroboehringerikemydshowamyef" + - "fectrentinosued-tirolmyfirewallonieruchomoscienceandindustrynmyf" + - "oruminamiyamashirokawanabelembetsukubankhmelnytskyivanylvenicemy" + - "fritzmyftpaccesshowtimelhusdecorativeartshriramsterdamnserverban" + - "iamyhome-servermyjinomykolaivaomymailermymediapchungnamdalseidfj" + - "ordyndns-ipartis-a-chefashionishiwakis-a-conservativegarsheis-a-" + - "cpadualstackhero-networkinggroupartsannanissandiegomyokohamamats" + - "udamypepinkmpspbargainstantcloudfunctionswedenvironmentalconserv" + - "ationionjukudoyamaintenancempresashibetsukuiiyamanouchikuhokuryu" + - "gasakitashiobarauthordalanddnslivelanddnss3-eu-west-1mypetsienar" + - "utolgamyphotoshibalena-devicesigdalmypictetrentinosuedtirolmypsx" + - "n--30rr7ymysecuritycamerakermyshopblocksilknx-serverrankoshigaya" + - "nagawamytis-a-bloggermytuleapioneermyvnchurcharternidyndns-mailu" + - "bindalublindesnesannohelplfinancialucaniamywirepaircraftingvollo" + - "mbardiamondsimple-urlpizzapkolobrzegersundplantsirdalplatformsha" + - "ngrilapyplazaplcube-serversaillesjcbnpparibaselburgplumbingoplur" + - "inacionalpodhalewismillerpodlasiellaktyubinskiptveterinaireadthe" + - "docscappgafannefrankfurtrentinsud-tirolpodzonepohlpoivronpokerpo" + - "krovskomaganepoliticarrdpolitiendapolkowicepoltavalle-aostathell" + - "ezajskomakiyosunndalpomorzeszowitdkomatsushimarylandponpesaro-ur" + - "bino-pesarourbinopesaromasvuotnaritakurashikis-into-animeguroros" + - "hinkamigotoyohashimototalponypordenonepornporsangerporsangugepor" + - "sgrunnanyokoshibahikariwanumatakkoebenhavnpoznanpraxis-a-bookkee" + - "perspectakashimarnardalprdpreservationpresidioprgmrprimelbournep" + - "rincipeprivatizehealthinsuranceproductionslupskomforbarreauction" + - "-webhostingjerstadotsuruokakamigaharautomotiveconomiasakuchinots" + - "uchiurakawalbrzycharitysfjordds3-eu-west-2profesionalprogressive" + - "nneslaskerrylogisticslzpromombetsurgeonshalloffameiwamasoyproper" + - "typrotectionprotonetrentinsudtirolprudentialpruszkowithgoogleapi" + - "sa-hockeynutsiracusakatamayufuelveruminanoprvcyberlevagangaviika" + - "nonjis-into-carshinshinotsurgeryprzeworskogptplusgardenpulawypup" + - "ippugliapvhagakhanamigawapvtrentinsued-tirolpwcircustomer-ocimdb" + - "ananarepublicaseihicampobassociatest-iservecounterstrikehimejibm" + - "deportevadsobetsumidatlanticasertaipeiheijiitatebayashiibajddarc" + - "hitecturealtorlandevelopmentattoobservereviewsaintlouis-a-bruins" + - "fanayorovnoceanographics3-fips-us-gov-west-1pzqhagebostadqldqpon" + - "iatowadaqslingqualifioappiszquickconnectrentinsuedtirolquicksyte" + - "stingquipelementsnoasaitoshimattelekommunikationqvcistrondheimmo" + - "bilienissayokkaichiropractichirurgiens-dentistes-en-francesuzaka" + - "nazawasuzukaneyamazoesuzukis-leetrentino-sudtirolsvalbardunloppa" + - "cificitichiryukyuragifuchungbukharaumalborkashiwarasveiosvelviko" + - "morotsukaminoyamaxunjargasvizzerasvn-reposomnarviikamishihoronob" + - "eauxartsandcraftsokndalswidnicartoonartdecologiaswidnikkokaminok" + - "awanishiaizubangeswiebodzin-butterswiftcoverswinoujscienceandhis" + - "toryswissmarterthanyousynology-diskstationsynology-dsooturystyka" + - "nmakiwientuscanytushuissier-justicetuvalle-daostaticsor-varanger" + - "tuxfamilytwmailvestfoldvestnesorfoldvestre-slidreplantationvestr" + - "e-totennishiawakuravestvagoyvevelstadvibo-valentiavibovalentiavi" + - "deovillasorocabalsan-sudtirollagdenesnaaseinet-freaksolarssonvin" + - "nicasacamdvrcampinagrandebuilderschlesischesorreisahayakawakamii" + - "chikawamisatottoris-into-cartoonshinshirovinnytsiavipsinaappitts" + - "burghofficialvirginiavirtual-userveftpiwatevirtualservervirtualu" + - "servegame-servervirtueeldomein-vigorlicevirtuelvisakegawaviterbo" + - "knowsitallvivolkenkundenvixn--32vp30haibarakitahatakanabeautysva" + - "rdoesntexisteingeekazunow-dnsevenassisicilyvlaanderenvladikavkaz" + - "imierz-dolnyvladimirvlogintoyonezawavminiserversicherungvologdan" + - "skongsbergvolvolkswagentsortlandvolyngdalvoorloperauniterois-los" + - "trolekamakurazakiwakunigamiharutwentevossevangenvotevotingvotoyo" + - "nowloclawekongsvingerwmflabsorumincomcastresindevicenzaporizhzhi" + - "awnextdirectrogstadworldworse-thandawowithyoutuberspacekitagatar" + - "getmyiphostrodawarawpdevcloudwritesthisblogsytewroclawiwatsukiyo" + - "notairestaurantroandinosaurepbodynamic-dnsopotrentoyonakagyokuto" + - "yakokonoewtcminnesotaketakazakis-an-actresshinjukumanowtvallee-d" + - "-aosteigenwtfastvps-serveronakanotoddenwuozuwzmiuwajimaxn--3oq18" + - "vl8pn36axn--3pxu8koninjambylxn--42c2d9axn--45br5cylxn--45brj9civ" + - "ilisationisshinguccircleverappsanokasukabedzin-berlindasdaburxn-" + - "-45q11civilizationiyodogawaxn--4gbriminingxn--4it168dxn--4it797k" + - "onskowolayangroupictureshirahamatonbetsurnadalxn--4pvxs4allxn--5" + - "4b7fta0ccivilwarmiastagets-itozsdeltajimidorissagaeroclubmedecin" + - "cinnationwidealerxn--55qw42gxn--55qx5dxn--5js045dxn--5rtp49clanb" + - "ibaidarmeniaxn--5rtq34konsulatrobeepilepsykkylvenetodayxn--5su34" + - "j936bgsgxn--5tzm5gxn--6btw5axn--6frz82gxn--6orx2rxn--6qq986b3xlx" + - "n--7t0a264cldmailovecollegefantasyleaguernseyxn--80adxhksoundcas" + - "tronomy-routerxn--80ao21axn--80aqecdr1axn--80asehdbarrell-of-kno" + - "wledgeiseiyoichippubetsubetsugarugbyglandroverhalla-speziautosca" + - "nadaeguambulanceobninskaracoldwarszawaukraanghkeymachinewhampshi" + - "realtydalaskanittedallasalleangaviikaascolipicenodumemergencyach" + - "ts3-ca-central-1xn--80aswgxn--80augustownproviderxn--8ltr62konyv" + - "elolipopiemontexn--8pvr4uxn--8y0a063axn--90a3academiamicaaarbort" + - "eaches-yogasawaracingxn--90aeroportalabamagasakishimabaraogakibi" + - "chuoxn--90aishobarakawagoexn--90azhytomyravendbarsycenterprisesa" + - "kikuchikuseikarugamvikarasjokarasuyamarshallstatebankaratemrhclo" + - "udiscountyombolzano-altoadigeometre-experts-comptables3-us-west-" + - "1xn--9dbhblg6dietciprianiigataishinomakinkobayashikaoirmitakehar" + - "axn--9dbq2axn--9et52uxn--9krt00axn--andy-iraxn--aroport-byandexc" + - "loudxn--asky-iraxn--aurskog-hland-jnbarsyonlinewhollandiscourses" + - "3-us-west-2xn--avery-yuasakuhokkaidownloadxn--b-5gaxn--b4w605fer" + - "dxn--balsan-sdtirol-nsbsouthcarolinarvikommunexn--bck1b9a5dre4cl" + - "ickasumigaurawa-mazowszextraspace-to-rentalstomakomaibaraxn--bdd" + - "dj-mrabdxn--bearalvhki-y4axn--berlevg-jxaxn--bhcavuotna-s4axn--b" + - "hccavuotna-k7axn--bidr-5nachikatsuuraxn--bievt-0qa2xn--bjarky-fy" + - "aotsurreyxn--bjddar-ptarnobrzegyptianxn--blt-elabourxn--bmlo-gra" + - "ingerxn--bod-2natalxn--bozen-sdtirol-2obanazawaxn--brnny-wuacade" + - "my-firewall-gatewayxn--brnnysund-m8accident-investigation-aptibl" + - "eadpagest-mon-blogueurovision-k3southwestfalenxn--brum-voagatrom" + - "sakakinokiaxn--btsfjord-9zaxn--bulsan-sdtirol-nsbashkiriaveroyke" + - "ngerdalcesurancechirealmpmnavigationavoizumizakibigawaurskog-hol" + - "andingdyniaetnabudapest-a-la-masion-riopretobamaceratabuseating-" + - "organicasadelamonedapliernewspapereportateshinanomachimkentateya" + - "mabogadobeaemcloud66xn--c1avgxn--c2br7gxn--c3s14misakis-an-anarc" + - "historicalsocietyxn--cck2b3basicservercelliguriavocatanzarowebsp" + - "acebinordreisa-geekaragandaustevoll-o-g-i-natuurwetenschappenaum" + - "burggfarmerseine164-baltimore-og-romsdalipayboltatsunobihirosaki" + - "kamijimatsuuragrocerybnikeisenbahnaturhistorisches3-ap-southeast" + - "-1kappchizip6xn--cckwcxetdxn--cesena-forl-mcbremangerxn--cesenaf" + - "orl-i8axn--cg4bkis-not-certifiedugit-pagespeedmobilizeroticahces" + - "uoloanshintokushimaxn--ciqpnxn--clchc0ea0b2g2a9gcdxn--comunicaes" + - "-v6a2oxn--correios-e-telecomunicaes-ghc29axn--czr694basilicatani" + - "avoues3-eu-west-3utilitiesquare7xn--czrs0tromsojamisonxn--czru2d" + - "xn--czrw28basketballyngenhktjeldsundiscoveryomitanoceanographiqu" + - "eu-1xn--d1acj3batochiokinoshimaizuruhrxn--d1alfaromeoxn--d1atrus" + - "teexn--d5qv7z876clinichitachinakagawashtenawdev-myqnapcloudeitys" + - "nesandvikcoromantovalle-d-aostatic-accessanfranciscofreakunemuro" + - "rangehirnrtoyotomiyazakis-a-celticsfanishinomiyashironoxn--davve" + - "njrga-y4axn--djrs72d6uyxn--djty4kooris-a-patsfanxn--dnna-grajewo" + - "lterskluwerxn--drbak-wuaxn--dyry-iraxn--e1a4cliniquenoharaxn--ec" + - "kvdtc9dxn--efvn9sowaxn--efvy88hair-surveillancexn--ehqz56nxn--el" + - "qq16hakatanortonxn--estv75gxn--eveni-0qa01gaxn--f6qx53axn--fct42" + - "9kopervikhersonxn--fhbeiarnxn--finny-yuaxn--fiq228c5hspeedpartne" + - "rsolognexn--fiq64batsfjordishakotanhlfanhs3-website-ap-northeast" + - "-1xn--fiqs8spjelkavikomonowruzhgorodeoxn--fiqz9spreadbettingxn--" + - "fjord-lraxn--fjq720axn--fl-ziaxn--flor-jraxn--flw351exn--forl-ce" + - "sena-fcbsspydebergxn--forlcesena-c8axn--fpcrj9c3dxn--frde-grandr" + - "apidsrlxn--frna-woaraisaijosoyrovigotsukisosakitagawaxn--frya-hr" + - "axn--fzc2c9e2clintonoshoesantabarbaraxn--fzys8d69uvgmailxn--g2xx" + - "48clothingdustdataitogitsuldalucernexn--gckr3f0fauskedsmokorseta" + - "gayaseralingenoamishirasatogokasells-for-lessasebofageologyxn--g" + - "ecrj9cn-northwest-1xn--ggaviika-8ya47hakodatexn--gildeskl-g0axn-" + - "-givuotna-8yasakaiminatoyookaniepcexn--gjvik-wuaxn--gk3at1exn--g" + - "ls-elacaixaxn--gmq050is-savedunetflixilxn--gmqw5axn--h-2failxn--" + - "h1aeghakonexn--h2breg3evenesrvaporcloudxn--h2brj9c8cngroks-thisa" + - "yamanobeokakegawaxn--h3cuzk1digitalxn--hbmer-xqaxn--hcesuolo-7ya" + - "35bauhausposts-and-telecommunications3-website-ap-southeast-1xn-" + - "-hery-iraxn--hgebostad-g3axn--hkkinen-5waxn--hmmrfeasta-s4accide" + - "nt-prevention-rancherkasydneyxn--hnefoss-q1axn--hobl-iraxn--holt" + - "len-hxaxn--hpmir-xqaxn--hxt814exn--hyanger-q1axn--hylandet-54axn" + - "--i1b6b1a6a2exn--imr513nxn--indery-fyasugivingxn--io0a7is-slickh" + - "arkivalleeaosteinkjerusalembroideryxn--j1aefbsbxn--12cfi8ixb8lxn" + - "--j1amhakubahccavuotnagaraholtalenglandxn--j6w193gxn--jlq480n2rg" + - "xn--jlq61u9w7beneventoeidsvollimanowarudaxaustinnaval-d-aosta-va" + - "lleyokosukanumazuryokoteastcoastaldefenceatonsbergjemnes3-eu-cen" + - "tral-1xn--jlster-byasuokanoyakumoldeloittenrikuzentakataiwanairf" + - "orcebetsuikidsmynasushiobaragusartstorfjordxn--jrpeland-54axn--j" + - "vr189misasaguris-an-artistgoryxn--k7yn95exn--karmy-yuaxn--kbrq7o" + - "xn--kcrx77d1x4axn--kfjord-iuaxn--klbu-woaxn--klt787dxn--kltp7dxn" + - "--kltx9axn--klty5xn--3bst00mintelligencexn--koluokta-7ya57hakuis" + - "-a-hunterxn--kprw13dxn--kpry57dxn--kpu716fbx-osaskatchewanxn--kp" + - "ut3is-uberleetrentino-sued-tirolxn--krager-gyatomitamamuraxn--kr" + - "anghke-b0axn--krdsherad-m8axn--krehamn-dxaxn--krjohka-hwab49jdfa" + - "stlylbanzaicloudcontrolledekagaminombresciaustraliajudaicable-mo" + - "democraciabruzzoologicalvinklein-addrammenuorochesterimo-i-ranaa" + - "mesjevuemielno-ipifonyc66xn--ksnes-uuaxn--kvfjord-nxaxn--kvitsy-" + - "fyatsukanraxn--kvnangen-k0axn--l-1fairwindstorjdevcloudnshinyosh" + - "itomiokamitondabayashiogamagoriziaxn--l1accentureklamborghinikol" + - "aeventstpetersburgxn--laheadju-7yatsushiroxn--langevg-jxaxn--lcv" + - "r32dxn--ldingen-q1axn--leagaviika-52bentleyonagoyaxn--lesund-hua" + - "xn--lgbbat1ad8jelenia-goraxn--lgrd-poacctrvareservehalflifestyle" + - "xn--lhppi-xqaxn--linds-pramericanartrycloudflarezzoxn--lns-qlaqu" + - "ilanstreamswatch-and-clockerxn--loabt-0qaxn--lrdal-sraxn--lrensk" + - "og-54axn--lt-liacnpyatigorskodjeffersonxn--lten-granexn--lury-ir" + - "axn--m3ch0j3axn--mely-iraxn--merker-kuaxn--mgb2ddestudioxn--mgb9" + - "awbfbxosassaris-a-democratrapaniizaxn--mgba3a3ejtrysiljanxn--mgb" + - "a3a4f16axn--mgba3a4franamizuholdingstudynamisches-dnsolundbeckom" + - "munalforbundxn--mgba7c0bbn0axn--mgbaakc7dvfedorapeoplegnicanonoi" + - "chinomiyakexn--mgbaam7a8hakusanagochijiwadell-ogliastraderxn--mg" + - "bab2bdxn--mgbah1a3hjkrdxn--mgbai9a5eva00beppublishproxyzgorzelec" + - "coffeedbackplaneapplicationcloudappspotagerxn--mgbai9azgqp6jeonn" + - "amerikawauexn--mgbayh7gpaleoxn--mgbbh1a71exn--mgbc0a9azcgxn--mgb" + - "ca7dzdoxn--mgberp4a5d4a87gxn--mgberp4a5d4arxn--mgbgu82axn--mgbi4" + - "ecexposedxn--mgbpl2fhskydivingxn--mgbqly7c0a67fbcnsantacruzsanta" + - "fedjejuifmetlifeinsurancexn--mgbqly7cvafranziskanerimaringatlant" + - "akahashimamakiryuohdattowebcampinashikiminohostre-totendofintern" + - "et-dnsaliasiaxn--mgbt3dhdxn--mgbtf8flatangerxn--mgbtx2beskidyn-i" + - "p24xn--mgbx4cd0abbvieeexn--mix082fedoraprojectravelchannelxn--mi" + - "x891feiraquarelleaseeklogesaudaxn--mjndalen-64axn--mk0axin-dslgb" + - "tunesor-odalxn--mk1bu44cntrani-andria-barletta-trani-andriaxn--m" + - "kru45is-very-badajozxn--mlatvuopmi-s4axn--mli-tlarvikoryokamikaw" + - "anehonbetsurutaharaxn--mlselv-iuaxn--moreke-juaxn--mori-qsakurag" + - "awaxn--mosjen-eyawaraxn--mot-tlavagiskexn--mre-og-romsdal-qqbuse" + - "rveexchangexn--msy-ula0haldenxn--mtta-vrjjat-k7aflakstadaokagaki" + - "cks-assnasaarlandxn--muost-0qaxn--mxtq1misawaxn--ngbc5azdxn--ngb" + - "e9e0axn--ngbrxn--3ds443gxn--nit225kosaigawaxn--nmesjevuemie-tcba" + - "lsan-suedtirolkuszczytnoipirangalsacexn--nnx388axn--nodessakurai" + - "s-very-evillagexn--nqv7fs00emaxn--nry-yla5gxn--ntso0iqx3axn--nts" + - "q17gxn--nttery-byaeservehttpixolinoxn--nvuotna-hwaxn--nyqy26axn-" + - "-o1acheltenham-radio-openairbusantiquest-a-la-maisondre-landroid" + - "xn--o3cw4halsaikitahiroshimaoris-a-knightpointtohobby-sitexn--o3" + - "cyx2axn--od0algxn--od0aq3bestbuyshouses3-website-ap-southeast-2x" + - "n--ogbpf8flekkefjordxn--oppegrd-ixaxn--ostery-fyawatahamaxn--osy" + - "ro-wuaxn--otu796dxn--p1acfermochizukirovogradoyxn--p1ais-very-go" + - "odyearxn--pbt977coguchikuzenxn--pgbs0dhlxn--porsgu-sta26ferrarax" + - "n--pssu33lxn--pssy2uxn--q9jyb4collectionxn--qcka1pmckinseyxn--qq" + - "qt11misconfusedxn--qxa6axn--qxamuneustargardxn--rady-iraxn--rdal" + - "-poaxn--rde-ulavangenxn--rdy-0nabaris-very-nicexn--rennesy-v1axn" + - "--rhkkervju-01aferraris-a-designerxn--rholt-mragowoodsidemoneyxn" + - "--rhqv96gxn--rht27zxn--rht3dxn--rht61exn--risa-5nativeamericanan" + - "tiquestuff-4-salexn--risr-iraxn--rland-uuaxn--rlingen-mxaxn--rms" + - "kog-byaxn--rny31hammarfeastafricapetownnews-stagingxn--rovu88bet" + - "ainaboxfusejnyonagunicommbankaratsuginamikatagamilitaryoriikarel" + - "ianceu-2xn--rros-granvindafjordxn--rskog-uuaxn--rst-0naturalhist" + - "orymuseumcenterxn--rsta-francaiseharaxn--rvc1e0am3exn--ryken-vua" + - "xn--ryrvik-byaxn--s-1faithamurakamigoris-a-landscaperugiaxn--s9b" + - "rj9colognexus-2xn--sandnessjen-ogbhzcateringebuildingjesdalimite" + - "diskussionsbereichaseljeepsondriodejaneirockartuzyoshiokanzakiyo" + - "kawaraxn--sandy-yuaxn--sdtirol-n2axn--seral-lraxn--ses554gxn--sg" + - "ne-gratangenxn--skierv-utazastufftoread-booksnesolutionsokananii" + - "mihoboleslawiecitadeliveryggeexn--skjervy-v1axn--skjk-soaxn--skn" + - "it-yqaxn--sknland-fxaxn--slat-5naturalsciencesnaturellestuttgart" + - "revisohughesomaxn--slt-elabcieszynxn--smla-hraxn--smna-gratis-a-" + - "bulls-fanxn--snase-nraxn--sndre-land-0cbieigersundisrechtraining" + - "jovikariyaltakasugaincheonikonanporocpanamatsuzakindianapolis-a-" + - "anarchistoireggiocalabriaxn--snes-poaxn--snsa-roaxn--sr-aurdal-l" + - "8axn--sr-fron-q1axn--sr-odal-q1axn--sr-varanger-ggbielawalmartjm" + - "axxxboxenapponazure-mobileu-3xn--srfold-byaxn--srreisa-q1axn--sr" + - "um-grazxn--stfold-9xaxn--stjrdal-s1axn--stjrdalshalsen-sqbiellaa" + - "kesvuemielecceu-4xn--stre-toten-zcbieszczadygeyachimataikikugawa" + - "ltervistaprinternationalfirearms3-website-eu-west-1xn--t60b56axn" + - "--tckweatherchannelxn--tiq49xqyjetztrentino-suedtirolxn--tjme-hr" + - "axn--tn0agrinetbankosakaerodromegallupinbarrel-of-knowledgestack" + - "arasjohkamikoaniikappuboliviajessheimetacentrumeteorappalmaserat" + - "in-the-bandain-vpncasinordkappalmspringsakerevistaples3-us-gov-w" + - "est-1xn--tnsberg-q1axn--tor131oxn--trany-yuaxn--trentin-sd-tirol" + - "-rzbievat-band-campaniaxn--trentin-sdtirol-7vbifukagawashingtond" + - "clkarlsoyukindianmarketingladefinimakanegasakiraxn--trentino-sd-" + - "tirol-c3bigv-infoodnetworkangerxn--trentino-sdtirol-szbihorology" + - "ukuhashimoichinosekigaharaxn--trentinosd-tirol-rzbikedaejeonbukl" + - "ugsmileborkdalvdalaheadjudygarlandivtasvuodnakaiwamizawatchandcl" + - "ockarmoyurihonjournalistjohninohekinannestadivttasvuotnakamagaya" + - "habahcavuotnagaivuotnagaokakyotambabydgoszczecinemagentositelema" + - "rkarpaczeladzjampagefrontappanasonicatholicaxiashorokanaievje-og" + - "-hornnes3-website-sa-east-1xn--trentinosdtirol-7vbilbaokinawashi" + - "rosatochigiessensiositecnologiaxn--trentinsd-tirol-6vbillustrati" + - "onredumbrellahppiacenzachpomorskieninomiyakonojorpelandiyusuhara" + - "xn--trentinsdtirol-nsbioddaxn--trgstad-r1axn--trna-woaxn--troms-" + - "zuaxn--tysvr-vraxn--uc0atvarggatritonxn--uc0ay4axn--uist22handso" + - "nyoursidellogliastradingxn--uisz3gxn--unjrga-rtarumizusawaxn--un" + - "up4yxn--uuwu58axn--vads-jraxn--valle-aoste-ebbtunkomvuxn--2scrj9" + - "christmasakindlefrakkestadyndns-homednsanjotoyouraxn--valle-d-ao" + - "ste-ehbodollsusakis-into-gamessinazawaxn--valleaoste-e7axn--vall" + - "edaoste-ebbvacationsusonoxn--vard-jraxn--vegrshei-c0axn--vermgen" + - "sberater-ctbirdartcenterprisecloudcontrolapplebtimnetzlglassassi" + - "nationalheritagexn--vermgensberatung-pwbirkenesoddtangenovaranza" + - "nquanpachigasakievennodesabaerobatickets3-website-us-east-1xn--v" + - "estvgy-ixa6oxn--vg-yiabkhaziaxn--vgan-qoaxn--vgsy-qoa0jevnakersh" + - "uscultureggioemiliaromagnamsosnowiechristiansburgriwataraidyndns" + - "-freeboxosloftranakaniikawatanaguraxn--vgu402colonialwilliamsbur" + - "grondarxn--vhquvaroyxn--vler-qoaxn--vre-eiker-k8axn--vrggt-xqadx" + - "n--vry-yla5gxn--vuq861birthplacexn--w4r85el8fhu5dnraxn--w4rs40lx" + - "n--wcvs22dxn--wgbh1coloradoplateaudioxn--wgbl6axn--xhq521bjarkoy" + - "usuisservehumourxn--xkc2al3hye2axn--xkc2dl3a5ee0hangglidingxn--y" + - "9a3aquariumishimasudaxn--yer-znaturbruksgymnxn--yfro4i67oxn--yga" + - "rden-p1axn--ygbi2ammxn--3e0b707exn--ystre-slidre-ujbjerkreimbamb" + - "lebesbyeniwaizumiotsukumiyamazonawsmpplanetariumemorialillyolasi" + - "tebizenakanojoetsuwanouchikujogaszkolancashirecreationavuotnaple" + - "s3-external-1xn--zbx025dxn--zf0ao64axn--zf0avxn--3hcrj9civilavia" + - "tionissedaluccapitalonewportlligatoystre-slidrettozawaxn--zfr164" + - "bjugnieznord-frontierxnbayxz" + "eksvikaracoldwarszawabogadobeaemcloud66bjarkoyusuharabjerkreimdb" + + "altimore-og-romsdalipayokozebizenakanotoddenavuotnarashinobninsk" + + "aragandaustevoll-o-g-i-naval-d-aosta-valleyboltateshinanomachimk" + + "entateyamagrocerybnikeisenbahn4tatarantours3-ap-northeast-2ix443" + + "2-balsan-suedtirolkuszczytnoipirangamvik12bjugnieznord-frontierb" + + "lackfridayusuisservehumourbloombergbauernishiazaindielddanuorrin" + + "digenamsosnowiechernihivgubs3-website-sa-east-1bloxcms3-website-" + + "us-east-1bluedaemoneyuu2-localhostoregontrailroadrayddnsfreebox-" + + "osascoli-picenordre-landraydns3-website-us-west-1bmoattachments3" + + "-website-us-west-2bms5yuzawabmwedeploybnrwegroweibolognagasakind" + + "eroybomloabathsbchernivtsiciliabondrivefsnillfjordrobaknoluoktac" + + "hikawakuyabukievennodesadoes-itvedestrandrudupontariobranconakan" + + "iikawatanagurabonnishigoddabookinghostfoldnavyboomlair-traffic-c" + + "ontrolleyboschaefflerdalivornohtawaramotoineppueblockbustermezja" + + "mpagefrontapparachutinglobalashovhachinohedmarkarpaczeladzlglobo" + + "avistanbulsan-sudtirolombardynaliaskimitsubatamibugattiffanycher" + + "novtsymantechnologybostikaruizawabostonakijinsekikogentappsselfi" + + "paraglidinglogoweirbotanicalgardenishiharabotanicgardenishiizuna" + + "zukindustriabotanynysagaeroclubmedecincinnationwidealerbouncemer" + + "ckmsdnipropetrovskjervoyageometre-experts-comptablesakyotanabell" + + "unord-aurdalpha-myqnapcloudaccesscambridgeiseiyoichippubetsubets" + + "ugarugbydgoszczecinemagentositecnologiabounty-fullensakerryprope" + + "rtiesalangenishikatakinoueboutiquebechirurgiens-dentistes-en-fra" + + "ncebozen-sudtirolomzaporizhzhegurindustriesteamfamberkeleybozen-" + + "suedtirolondrinapleskarumaifarmsteadurbanamexhibitionishikatsura" + + "git-reposalondonetskasaokamiminersaltdalorenskogloppenzaolbia-te" + + "mpio-olbiatempioolbialystokkepnogatagajobojinfinitintelligencebp" + + "lacedogawarabikomaezakirunorddalotenkawabrandywinevalleybrasilia" + + "brindisibenikindlebtimnetzparisor-fronishikawazukamisunagawabris" + + "toloseyouriparliamentjomeloyalistoragebritishcolumbialowiezagani" + + "shimerabroadcastleclerchiryukyuragifuchungbukharavennagatorodoyb" + + "roadwaybroke-itjxfinitybrokerbronnoysundurhamburglugmbhartipscbg" + + "minakamichiharabrothermesaverdealstahaugesunderseaportsinfolldal" + + "ottebrowsersafetymarketsaludweberbrumunddalottokonamegatakazakin" + + "ternationalfirearmsalvadordalibabalena-devicesalzburgmodellingmx" + + "javald-aostarnbergretakanabeautysvardoesntexisteingeekashibataka" + + "tsukiyosatokamachintaifun-dnsdojolsterbrunelastxn--0trq7p7nnishi" + + "nomiyashironomutashinaintuitkmaxxn--11b4c3dynathomebuiltwithdark" + + "ashiharabrusselsamegawabruxellesamnangerbryansklepparmattelekomm" + + "unikationishinoomotegobrynewhollandyndns-at-homedepotenzamamidsu" + + "ndyndns-at-workisboringrimstadyndns-blogdnsampalacebuskerudinewj" + + "erseybuzentsujiiebuzzwellbeingzonebwfarsundyndns-freeboxosloftra" + + "nakanojoetsuwanouchikujogaszkolancashirecreationishinoshimatsuur" + + "abzhitomirumalatvuopmicrolightingripebzzcommunexus-2community-pr" + + "ochowicecomoarekecomparemarkerryhotelsantacruzsantafedjejuifmetl" + + "ifeinsurancecompute-1computerhistoryofscience-fictioncomsecurity" + + "tacticsantamariakecondoshichinohealth-carereformitakeharaconfere" + + "nceconstructionconsuladonnaharimalopolskanlandyndns-remotewdyndn" + + "s-serverisignconsultanthropologyconsultingrpartycontactozsdeltaj" + + "irittogliattis-a-caterercontagematsubaracontemporaryarteducation" + + "alchikugodontexistmein-iservebeercontractorskenconventureshinode" + + "arthruherecipescaravantaacookingchannelsdvrdnsfor-better-thanawa" + + "tchandclockasukabedzin-berlindasdaburcooluroycooperativano-frank" + + "ivskolefrakkestadyndns-webhopencraftrani-andria-barletta-trani-a" + + "ndriacopenhagencyclopedichofunatoriginstitutemasekashiwaracoprod" + + "uctionsantoandreamhostersanukis-a-celticsfancorsicagliaricoharuo" + + "vatraniandriabarlettatraniandriacorvettemp-dnsaobernardocosenzak" + + "opanecosidnshome-webserverdalutskasumigaurawa-mazowszexnetnedalu" + + "xurycostumedicinakaiwamizawatchesaogoncartoonartdecologiacouchpo" + + "tatofriesaotomeldaluzerncouklugsmilegallocus-3councilvivanovolda" + + "couponsapporocq-acranbrookuwanalyticsardegnarusawacrdyndns-wikir" + + "kenesardiniacreditcardyndns-workshopitsitexaskoyabearalvahkikuch" + + "ikuseikarugalsacecreditunioncremonashgabadaddjaguarqcxn--12cfi8i" + + "xb8lcrewildlifedorainfracloudfrontdoorcricketrzyncrimeast-kazakh" + + "stanangercrotonecrownipasadenaritakurashikis-a-chefashioncrsvpas" + + "sagensarlcruisesarpsborgruecryptonomichigangwoncuisinellajollame" + + "ricanexpressexyculturalcentertainmentranoycuneocupcakecuritiback" + + "yardsarufutsunomiyawakasaikaitakofuefukihaboromskoguidegreecurva" + + "lled-aostaverncymrussiacyonabaruminamidaitomanchestercyouthachio" + + "jiyahooguyfetsundynnsasayamafgujohanamakinoharafhvalerfidoomdnst" + + "racefieldynservebbsasebofagemologicallyngenfigueresinstagingulen" + + "filateliafilegear-audnedalnfilegear-deatnulvikatowicefilegear-gb" + + "izfilegear-iefilegear-jpmorganfilegear-sgunmanxn--1ck2e1bananare" + + "publicasertairaumalborkarasjohkamikoaniikappuboliviajessheimemor" + + "ialaziobserverevistaples3-external-1filminamifuranofinalfinancef" + + "ineartsavonarutomobellevuelosangelesjabbottransurlfinlandynufcfa" + + "nfinnoyfirebaseappatriafirenzefirestonefirmdalegoldpoint2thisami" + + "tsukefishingolffansaxofitjarvodkafjordynv6fitnessettlementrapani" + + "izafjalerflesberguovdageaidnunusualpersonflickragerogerschoenbru" + + "nnflightschokokekschokoladenflirfloginlinefloraflorencefloridats" + + "unanjoburgushikamifuranorth-kazakhstanfloripaderbornfloristanoha" + + "takaharunzenflorokunohealthcareerscholarshipschoolschulezajskats" + + "ushikabeeldengeluidynvpnplus-4flowerschulserverfltravelchannelfl" + + "ynnhosting-clusterfndyroyrvikinguitarsaskatchewanfor-ourfor-some" + + "dizinhistorischeschwarzgwangjuniperfor-theaterforexrothachirogat" + + "akanezawaforgotdnschweizforli-cesena-forlicesenaforlillehammerfe" + + "ste-ipaviancarrdforsaleikangerforsandasuologoipfizerfortalfortmi" + + "ssoulancasterfortworthadanorthwesternmutualfosnesciencecentersci" + + "encehistoryfotaruis-a-cubicle-slavellinodeobjectscientistordalfo" + + "xfordebianfozorafredrikstadtvscjohnsonfreeddnsgeekgalaxyfreedesk" + + "topocznore-og-uvdalfreemasonryfreesitextileirfjordfreetlscotland" + + "freiburgwiddleitungsenfreseniuscountryestateofdelawareggio-calab" + + "riafribourgxn--1ctwolominamatarnobrzegyptianfriuli-v-giuliafriul" + + "i-ve-giuliafriuli-vegiuliafriuli-venezia-giuliafriuli-veneziagiu" + + "liafriuli-vgiuliafriuliv-giuliafriulive-giuliafriulivegiuliafriu" + + "livenezia-giuliafriuliveneziagiuliafriulivgiuliafrlfroganscrappe" + + "r-sitefrognfrolandfrom-akrehamnfrom-alfrom-arfrom-azfrom-capetow" + + "nnews-stagingfrom-coffeedbackplaneapplinzis-a-democratravelersin" + + "surancefrom-ctrdfrom-dchonanbulsan-suedtirolowiczest-le-patronis" + + "hitosashimizunaminamibosogndalpusercontentoyotapartsandnessjoeni" + + "shiwakinvestmentsandoyfrom-dedyn-berlincolnfrom-flanderscrapping" + + "from-gaulardalfrom-hichisochildrensgardenfrom-iafrom-idfrom-ilfr" + + "om-in-brbanzaicloudcontrolledekagaminombresciaustraliamusementdl" + + "lpages3-ap-south-1kappchizip6116-b-dataiji234lima-cityeatselinog" + + "radult3l3p0rtatamotors3-ap-northeast-1337from-kscrysechoseiroumu" + + "enchenissandiegofrom-kyowariasahikawafrom-lanciafrom-mamurogawaf" + + "rom-mdfrom-meeresistancefrom-mifunefrom-mnfrom-modalenfrom-mserv" + + "eirchoshibuyachiyodapliernewspaperfrom-mtnfrom-nctulangevagrigen" + + "tomologyeonggiehtavuoatnagahamaroyerfrom-ndfrom-nefrom-nh-serveb" + + "logsiteleafamilycompanyanagawafflecellclaimserveminecraftrentin-" + + "sud-tirolfrom-njaworznoticiasnesoddenmarkhangelskjakdnepropetrov" + + "skiervaapsteiermarkatsuyamarugame-hostrowiechoyodobashichikashuk" + + "ujitawarafrom-nminamiiserniafrom-nvalledaostargetmyiphostrodawar" + + "afrom-nyfrom-ohkurafrom-oketogurafrom-orfrom-padovaksdalfrom-pra" + + "tohmandalfrom-ris-a-designerfrom-schmidtre-gauldalfrom-sdfrom-tn" + + "from-txn--1lqs03nfrom-utsiracusaikisarazurecontainerdpolicefrom-" + + "val-daostavalleyfrom-vtrentin-sudtirolfrom-wafrom-wielunnerfrom-" + + "wvallee-aosteroyfrom-wyfrosinonefrostalowa-wolawafroyahikobierzy" + + "cefstcgroupgfoggiafujiiderafujikawaguchikonefujiminokamoenairlin" + + "edre-eikerfujinomiyadattowebcampinashikiminohostre-totendofinter" + + "net-dnsaliasiafujiokayamangonohejis-a-doctorayfujisatoshonairpor" + + "tland-4-salernoboribetsuckservemp3fujisawafujishiroishidakabirat" + + "oridefenseljordfujitsurugashimangyshlakasamatsudovre-eikerfujixe" + + "roxn--1lqs71dfujiyoshidavvenjargap-northeast-3fukayabeatservep2p" + + "harmacienservepicservequakefukuchiyamadavvesiidappnodebalancerti" + + "ficationfukudominichristiansburgrondarfukuis-a-financialadvisor-" + + "aurdalfukumitsubishigakishiwadazaifudaigojomedio-campidano-medio" + + "campidanomediofukuokazakisofukushimaniwakuratefukuroishikarikatu" + + "rindalfukusakisosakitagawafukuyamagatakahatakaishimoichinosekiga" + + "harafunabashiriuchinadafunagatakamatsukawafunahashikamiamakusats" + + "umasendaisennangooglecodespotrentin-sued-tirolfundaciofuoiskujuk" + + "uriyamannorfolkebibleirvikaufenfuosskoczowilliamhillfurnitureggi" + + "o-emilia-romagnakatombetsumitakagiizefurubirafurudonostiaafuruka" + + "wairtelebitbridgestonekobayashikshacknetcimbarcelonagawalmartatt" + + "oolforgehimejiitatebayashijonawatempresashibetsukuiiyamanouchiku" + + "hokuryugasakitaurayasudaustrheimatunduhrennesoyokosukanumazuryok" + + "oteastcoastaldefenceatonsbergjerdrumemergencyachts3-ca-central-1" + + "fusodegaurafussaintlouis-a-anarchistoireggiocalabriafutabayamagu" + + "chinomigawafutboldlygoingnowhere-for-morenakatsugawafuttsurugimp" + + "eriafuturecmservesarcasmatartanddesignfuturehostingfuturemailing" + + "fvgfylkesbiblackbaudcdn77-securebungoonord-odalfyresdalhangoutsy" + + "stemscloudhannanmokuizumodenaklodzkochikushinonsenergyhannosegaw" + + "ahanyuzenhapmircloudharstadharvestcelebrationhasamarburghasamina" + + "mi-alpsharis-a-hunterhashbanghasudahasura-appharmacysharphdfcban" + + "kazoologyhasvikazunow-dnshawaiijimaritimoduminamimakis-a-knightp" + + "ointtohobby-sitehatogayaitakaokalmykiahatoyamazakitakamiizumisan" + + "ofidelityhatsukaichikaiseiheijis-a-landscaperugiahattfjelldalhay" + + "ashimamotobungotakadagestangeorgeorgiahazuminobusells-for-usrcfa" + + "stlylbamblebesbyglandroverhalla-speziaustinnavigationavoizumizak" + + "ibigawajudaicable-modemocraciabruzzoologicalvinklein-addrammenuo" + + "rochesterimo-i-ranaamesjevuemielno-ipifonyaaarborteaches-yogasaw" + + "aracingdyniaetnabudapest-a-la-masion-riopretobamaceratabuseating" + + "-organic66helsinkitakatakarazukaluganskygearapphiladelphiaareadm" + + "yblogspotrentino-a-adigehembygdsforbundhemneshellaspeziahemsedal" + + "hepforgeherokussldheroyhgtvallee-d-aosteigenhidorahigashiagatsum" + + "agoianiahigashichichibunkyonanaoshimageandsoundandvisionthewifia" + + "tmallorcadaqueshimokawahigashihiroshimanehigashiizumozakitakyush" + + "uaiahigashikagawahigashikagurasoedahigashikawakitaaikitamihamada" + + "higashikurumeetrentino-aadigehigashimatsushimarcheapigeelvinckdd" + + "iethnologyhigashimatsuyamakitaakitadaitoigawahigashimurayamamoto" + + "rcycleshimokitayamahigashinarusells-itrentino-alto-adigehigashin" + + "ehigashiomihachimanagementrentino-altoadigehigashiosakasayamanak" + + "akogawahigashishirakawamatakasagoppdalhigashisumiyoshikawaminami" + + "aikitamotosumy-gatewayhigashitsunoshiroomurahigashiurausukitanak" + + "agusukumodernhigashiyamatokoriyamanashiibahccavuotnagareyamainte" + + "nancehigashiyodogawahigashiyoshinogaris-a-lawyerhiraizumisatohno" + + "shoooshikamaishimofusartshimonitayanagithubusercontentrentino-s-" + + "tirolhirakatashinagawahiranairtrafficplexus-1hirarahiratsukagawa" + + "hirayaizuwakamatsubushikusakadogawahistorichouseshimonosekikawah" + + "itachiomiyagildeskaliszhitachiotagotembaixadahitraeumtgeradelmen" + + "horstalbanshimosuwalkis-a-liberalhjartdalhjelmelandholeckodairah" + + "olidayhomeiphilatelyhomelinkitoolsztynsettlershimotsukehomelinux" + + "n--1qqw23ahomeofficehomesecuritymacaparecidahomesecuritypchristm" + + "aseratiresandvikcoromantovalle-d-aostatic-accessanfranciscofreak" + + "unemurorangehirnrtoyotomiyazakinzais-a-candidatehomesenseeringho" + + "meunixn--2m4a15ehondahongotpantheonsitehonjyoitakasakitashiobara" + + "hornindalhorsellsyourhomegoodshimotsumahorteneis-a-libertarianho" + + "spitalhoteleshinichinanhotmailhoyangerhoylandetroitskypehumaniti" + + "eshinjournalismailillesandefjordhurdalhurumajis-a-linux-useranis" + + "hiaritabashikaoirminamiminowahyllestadhyogoris-a-llamarriottrent" + + "ino-stirolhyugawarahyundaiwafuneis-very-badajozis-very-evillagei" + + "s-very-goodyearis-very-niceis-very-sweetpepperis-with-thebandois" + + "leofmanaustdaljevnakershuscultureggioemiliaromagnamsskoganeis-a-" + + "nascarfanjewelryjewishartgalleryjfkharkivalleedaostejgorajlljls-" + + "sto1jmphotographysiojnjcphonefosshintomikasaharajoyentrentino-su" + + "edtiroljoyokaichibajddarchitecturealtorlandjpnjprshiojirishirifu" + + "jiedajurkosherbrookegawakoshimizumakizunokunimimatakayamarylandk" + + "oshunantankhersonkosugekotohiradomainsurehabmerkotourakouhokutam" + + "akis-a-patsfankounosupplieshirakokaminokawanishiaizubangekouyama" + + "shikekouzushimashikis-a-personaltrainerkozagawakozakis-a-photogr" + + "apherokuapphilipsyno-dshinjukumanowtvalleeaosteinkjerusalembroid" + + "erykozowindmillkpnkppspdnshiranukamitsuekrasnikahokutokashikis-a" + + "-playershifteditchyouriphoenixn--2scrj9chromedicaltanissettaishi" + + "nomakinkobeardubaiduckdnsangokrasnodarkredstonekristiansandcatsh" + + "iraois-a-republicancerresearchaeologicaliforniakristiansundkrods" + + "heradkrokstadelvaldaostarostwodzislawindowskrakowinnershiraokamo" + + "gawakryminamioguni5kumatorinokumejimasoykumenantokigawakunisakis" + + "-a-rockstarachowicekunitachiarailwaykunitomigusukumamotoyamashik" + + "okuchuokunneppubtlshiratakahagitlaborkunstsammlungkunstunddesign" + + "kuokgroupilotshishikuis-a-socialistdlibestadkureisenkurgankurobe" + + "laudibleasingleshisognekurogiminamiashigarakuroisoftwarezzokurom" + + "atsunais-a-soxfankurotakikawasakis-a-studentalkushirogawakustana" + + "is-a-teacherkassyncloudkusupplykutchanelkutnokuzumakis-a-techiet" + + "is-a-musiciankvafjordkvalsundkvamlidlugolekadenagaivuotnagaokaky" + + "otambabyenebakkeshibechambagriculturennebudejjuedischesapeakebay" + + "ernukvanangenkvinesdalkvinnheradkviteseidatingkvitsoykwpspectrum" + + "inamisanrikubetsurfastvps-serveronakasatsunairguardiannakadomari" + + "nebraskauniversitychyattorneyagawakembuchikumagayagawakkanaibets" + + "ubamericanfamilydsclouderackmazerbaijan-mayen-rootaribeiraogashi" + + "madachicagoboatsassaris-a-conservativegarsheis-a-cpadualstackher" + + "o-networkinggroupassenger-associationkzmissileluxembourgmisugito" + + "kuyamatsumotofukemitourismolanxesshitaramamitoyoakemiuramiyazure" + + "websiteshikagamiishibukawamiyotamanomjondalenmlbfanmontrealestat" + + "efarmequipmentrentinoa-adigemonza-brianzapposhizukuishimogosenmo" + + "nza-e-della-brianzaptokyotangotsukitahatakamoriokakegawamonzabri" + + "anzaramonzaebrianzamonzaedellabrianzamoonscaleforcemordoviamoriy" + + "amatsunomoriyoshiminamiawajikis-an-actormormonstermoroyamatsusak" + + "ahoginankokubunjis-an-actresshinshinotsurgerymortgagemoscowioshi" + + "zuokanagawamoseushistorymosjoenmoskeneshoppingmosshopwarendalenu" + + "gmosvikhmelnytskyivaomoteginowaniihamatamakawajimansionshoujis-a" + + "n-anarchistoricalsocietymoviemovimientolgamozilla-iotrentinoaadi" + + "gemtranbymuenstermuginozawaonsenmuikamisatokaizukamikitayamatsur" + + "is-an-artistgorymukoebenhavnmulhouseoullensvanguardmunakatanemun" + + "cienciamuosattemupimientakkoelnmurmanskhplaystation-cloudmurotor" + + "craftrentinoalto-adigemusashimurayamatsushigemusashinoharamuseet" + + "rentinoaltoadigemuseumverenigingmusicargodaddyn-vpndnshowamutsuz" + + "awamy-vigorgemy-wanggouvichungnamdalseidfjordyndns-mailubindalub" + + "lindesnesanjotoyotsukaidomyactivedirectorymyasustor-elvdalmycdn7" + + "7-sslattuminamitanemydattolocalhistorymyddnskingmydissentrentino" + + "s-tirolmydobisshikis-an-engineeringmydroboehringerikemydshowtime" + + "lhusdecorativeartshriramsterdamnserverbaniamyeffectrentinostirol" + + "myfastly-terrariuminamiuonumasudamyfirewallonieruchomoscienceand" + + "industrynmyforuminamiyamashirokawanabelembetsukubankhmelnitskiya" + + "marumorimachidamyfritzmyftpaccesshwitdklabudhabikinokawabarthads" + + "electrentin-suedtirolmyhome-servermyjinomykolaivaporcloudmymaile" + + "rmymediapchurcharternidyndns-office-on-the-webhareidsbergentingr" + + "ongausdalucaniamyokohamamatsudamypepinkmpspbarclays3-sa-east-1my" + + "petsienarviikamishihoronobeauxartsandcraftsigdalmyphotoshibalati" + + "nogiftsilknx-serversailleshioyandexcloudmypictetrentinosud-tirol" + + "mypsxn--32vp30haebaruericssongdalenviknakayamaoris-a-geekautokei" + + "notteroymysecuritycamerakermyshopblocksimple-urlmytis-a-bookkeep" + + "erspectakasugais-an-entertainermytuleaprendemasakikonaikawachina" + + "ganoharamcoachampionshiphoptobishimadridvagsoygardendoftheintern" + + "etlifyis-bytomaritimekeepingmyvncircustomer-ociprianiigataitogit" + + "suldaluccarbonia-iglesias-carboniaiglesiascarboniamywirepbodynam" + + "ic-dnsirdalplatformshangrilapyplatter-appioneerplatterpippugliap" + + "lazaplcube-serversicherungplumbingoplurinacionalpodhalevangerpod" + + "lasiellaktyubinskiptveterinaireadthedocscappgafannefrankfurtrent" + + "inosudtirolpodzonepohlpoivronpokerpokrovskomakiyosunndalpolitica" + + "rrierpolitiendapolkowicepoltavalle-aostathellewismillerpomorzesz" + + "owithgoogleapiszponpesaro-urbino-pesarourbinopesaromasvuotnaroyp" + + "onypordenonepornporsangerporsangugeporsgrunnanyokoshibahikariwan" + + "umatamayufuelveruminanopoznanpraxis-a-bruinsfanprdpreservationpr" + + "esidioprgmrprimelbourneprincipeprivatizehealthinsuranceprofesion" + + "alprogressivenneslaskerrylogisticslupskomatsushimarylhurstjordal" + + "shalsenpromombetsurgeonshalloffameiwamassa-carrara-massacarraram" + + "assabusinessebyklecznagasukepropertyprotectionprotonetrentinosue" + + "d-tirolprudentialpruszkowithyoutuberspacekitagatargivestbytemark" + + "omforbarefootballooningjerstadotsuruokakamigaharauthordalandds3-" + + "eu-central-1prvcyberlevagangaviikanonjis-certifieducatorahimeshi" + + "mamateramobaraprzeworskogptplusgardenpulawypupittsburghofficialp" + + "vhagakhanamigawapvtrentinosuedtirolpwcistrondheimmobilienissayok" + + "kaichiropractichitachinakagawassamukawatarightathomeftparocherni" + + "governmentksatxn--12c1fe0bradescorporationrenderpzqhagebostadqld" + + "qponiatowadaqslingqualifioappiwatequickconnectrentinsud-tirolqui" + + "cksytestingquipelementslzqvcitadeliveryggeesusonosuzakanazawasuz" + + "ukaneyamazoesuzukis-into-animegurownprovidersvalbardunloppacific" + + "ivilaviationissedalucernesveiosvelvikomorotsukaminoyamaxunjargas" + + "vizzerasvn-reposologneswidnicasacamdvrcampinagrandebuilderschles" + + "ischesolundbeckommunalforbundswidnikkokonoeswiebodzin-butterswif" + + "tcoverswinoujscienceandhistoryswissmarterthanyousynology-disksta" + + "tionsynology-dsolutionsnoasakakinokiaturystykanmakiwientuscanytu" + + "shuissier-justicetuvalle-daostaticsootuxfamilytwmailvestnesopotr" + + "entinsudtirolvestre-slidreviewsaitoshimayfirstockholmestrandvest" + + "re-totennishiawakuravestvagoyvevelstadvibo-valentiavibovalentiav" + + "ideovillasor-odalvinnicasadelamonedancevinnytsiavipsinaappixolin" + + "ovirginiavirtual-userveftpizzavirtualservervirtualuservegame-ser" + + "vervirtueeldomein-vigorlicevirtuelvisakegawaviterboknowsitallviv" + + "olkenkundenvixn--3bst00miniservervlaanderenvladikavkazimierz-dol" + + "nyvladimirvlogintoyonezawavminnesotaketaketomisatokorozawavologd" + + "anskongsbergvolvolkswagentsor-varangervolyngdalvoorloperaunitero" + + "is-into-carshinshirovossevangenvotevotingvotoyonowmflabsorfoldwn" + + "extdirectroandinosaureplantationworldworse-thandawowiwatsukiyono" + + "tairestaurantritonwpdevcloudwritesthisblogsytewroclawloclawekong" + + "svingerwtcminterepaircraftingvollombardiamondshisuifuettertdasne" + + "tzwtfauskedsmokorsetagayaseralingenoamishirasatogokasells-for-le" + + "ssaudawuozuwzmiuwajimaxn--42c2d9axn--45br5cylxn--45brj9civilizat" + + "ionxn--45q11civilwarmiastagets-itoyouraxn--4gbriminingxn--4it168" + + "dxn--4it797konskowolayangroupictureshirahamatonbetsurnadalxn--4p" + + "vxs4allxn--54b7fta0cclanbibaidarmeniaxn--55qw42gxn--55qx5dxn--5j" + + "s045dxn--5rtp49cldmailovecollegefantasyleaguernseyxn--5rtq34kons" + + "ulatrobeepilepsykkylvenetodayxn--5su34j936bgsgxn--5tzm5gxn--6btw" + + "5axn--6frz82gxn--6orx2rxn--6qq986b3xlxn--7t0a264clic20001wwwhosw" + + "hokksundyndns-picsannohelplfinancialukowiiheyakagexn--80adxhksor" + + "ocabalestrandabergamo-siemensncfdxn--80ao21axn--80aqecdr1axn--80" + + "asehdbarreauction-webhostingjesdalillyolasitemrxn--80aswgxn--80a" + + "ugustowmcloudxn--8ltr62konyvelolipopiemontexn--8pvr4uxn--8y0a063" + + "axn--90a3academiamicaarpkomaganexn--90aeroportalabamagasakishima" + + "baraogakibichuoxn--90aishobarakawagoexn--90azhytomyravendbarrel-" + + "of-knowledgeapplicationcloudappspotagerxn--9dbhblg6digitalxn--9d" + + "bq2axn--9et52uxn--9krt00axn--andy-iraxn--aroport-byaotsurreyxn--" + + "asky-iraxn--aurskog-hland-jnbarrell-of-knowledgestackarasjokaras" + + "uyamarshallstatebankarateu-1xn--avery-yuasakuhokkaidownloadxn--b" + + "-5gaxn--b4w605ferdxn--balsan-sdtirol-nsbsorreisahayakawakamiichi" + + "kawamisatottoris-foundationxn--bck1b9a5dre4clickashiwazakiyosemi" + + "texn--bdddj-mrabdxn--bearalvhki-y4axn--berlevg-jxaxn--bhcavuotna" + + "-s4axn--bhccavuotna-k7axn--bidr-5nachikatsuuraxn--bievt-0qa2xn--" + + "bjarky-fyasakaiminatoyookaniepcexn--bjddar-ptarumizusawaxn--blt-" + + "elabourxn--bmlo-graingerxn--bod-2nativeamericanantiquesortlandxn" + + "--bozen-sdtirol-2obanazawaxn--brnny-wuacademy-firewall-gatewayxn" + + "--brnnysund-m8accident-investigation-aptibleadpagest-mon-blogueu" + + "rovision-k3sorumincomcastresindevicenzaporizhzhiaxn--brum-voagat" + + "rogstadxn--btsfjord-9zaxn--bulsan-sdtirol-nsbarsycenterprisesaki" + + "kugawaltervistaikimobetsuitainaioirasebastopologyeongnamegawakay" + + "amagazineat-urlimanowarudautomotiveconomiasakuchinotsuchiurakawa" + + "lesundeportevadsobetsumidatlanticaseihicampobassociatest-iservec" + + "ounterstrikebinagisoccertmgrazimutheworkpccwebredirectmembers3-e" + + "u-west-1xn--c1avgxn--c2br7gxn--c3s14misakis-a-therapistoiaxn--cc" + + "k2b3barsyonlinewhampshirealtysnes3-us-gov-west-1xn--cckwcxetdxn-" + + "-cesena-forl-mcbremangerxn--cesenaforl-i8axn--cg4bkis-into-carto" + + "onshintokushimaxn--ciqpnxn--clchc0ea0b2g2a9gcdxn--comunicaes-v6a" + + "2oxn--correios-e-telecomunicaes-ghc29axn--czr694bashkiriautoscan" + + "adaeguambulanceobihirosakikamijimatsuzakibmdevelopmentatsunobira" + + "ukraanghkeymachineustargardd-dnsiskinkyotobetsulikes-piedmontice" + + "llodingenatuurwetenschappenaumburggfarmerseine164-balsfjorddnsli" + + "velanddnss3-ap-southeast-1xn--czrs0tromsakataobaomoriguchiharahk" + + "keravjuegoshikijobservableusercontentrentinsuedtirolxn--czru2dxn" + + "--czrw28basicservercelliguriaveroykenglandgcahcesuoloans3-eu-wes" + + "t-2xn--d1acj3basilicataniavocatanzarowebspacebinordreisa-hockeyn" + + "utazuerichardlikescandyn53utilitiesquare7xn--d1alfaromeoxn--d1at" + + "romsojamisonxn--d5qv7z876clinichocolatelevisionishiokoppegardynd" + + "ns-ipartinuyamashinatsukigatakashimarnardalouvreitoyosatoyokawax" + + "n--davvenjrga-y4axn--djrs72d6uyxn--djty4kooris-a-nursembokukitch" + + "enxn--dnna-grajewolterskluwerxn--drbak-wuaxn--dyry-iraxn--e1a4cl" + + "iniquenoharaxn--eckvdtc9dxn--efvn9soundcastronomy-routerxn--efvy" + + "88haibarakitahiroshimapartmentservicesevastopolexn--ehqz56nxn--e" + + "lqq16hair-surveillancexn--eveni-0qa01gaxn--f6qx53axn--fct429kope" + + "rvikharkovanylvenicexn--fhbeiarnxn--finny-yuaxn--fiq228c5hsouthc" + + "arolinatalxn--fiq64basketballfinanzgoravoues3-eu-west-3xn--fiqs8" + + "southwestfalenxn--fiqz9sowaxn--fjord-lraxn--fjq720axn--fl-ziaxn-" + + "-flor-jraxn--flw351exn--forl-cesena-fcbsspeedpartnersokananiimih" + + "oboleslawiecitichitosetogakushimotoganewportlligatmparsamsclubar" + + "towhalingriwataraidyndns-homednsamsungroks-thisayamanobeokakudam" + + "atsuexn--forlcesena-c8axn--fpcrj9c3dxn--frde-grandrapidspjelkavi" + + "komonowruzhgorodeoxn--frna-woaraisaijosoyrorospreadbettingxn--fr" + + "ya-hraxn--fzc2c9e2clintonoshoesanokasserverrankoshigayameinforum" + + "zxn--fzys8d69uvgmailxn--g2xx48clothingdustdataiwanairforcebetsui" + + "kidsmynasushiobaragusabaejrietisalatinabenonicbcn-north-1xn--gck" + + "r3f0fbsbxn--12co0c3b4evalleaostavangerxn--gecrj9cn-northwest-1xn" + + "--ggaviika-8ya47hakatanortonxn--gildeskl-g0axn--givuotna-8yasugi" + + "vingxn--gjvik-wuaxn--gk3at1exn--gls-elacaixaxn--gmq050is-into-ga" + + "messinazawaxn--gmqw5axn--h-2failxn--h1aeghakodatexn--h2breg3even" + + "espydebergxn--h2brj9c8cngrossetouchihayaakasakawaharaxn--h3cuzk1" + + "discountyxn--hbmer-xqaxn--hcesuolo-7ya35batochiokinoshimakeupowi" + + "at-band-campaniaxaurskog-holandingjemnes3-ap-southeast-2xn--hery" + + "-iraxn--hgebostad-g3axn--hkkinen-5waxn--hmmrfeasta-s4accident-pr" + + "evention-rancherkasydneyxn--hnefoss-q1axn--hobl-iraxn--holtlen-h" + + "xaxn--hpmir-xqaxn--hxt814exn--hyanger-q1axn--hylandet-54axn--i1b" + + "6b1a6a2exn--imr513nxn--indery-fyasuokanoyakumoldeloittenrikuzent" + + "akatajimidorissagamiharaxn--io0a7is-leetrentino-sud-tirolxn--j1a" + + "efbx-osauheradyndns1xn--j1amhakonexn--j6w193gxn--jlq480n2rgxn--j" + + "lq61u9w7batsfjordiscoveryombolzano-altoadigeologyomitanoceanogra" + + "phics3-us-west-1xn--jlster-byatomitamamuraxn--jrpeland-54axn--jv" + + "r189misasaguris-an-accountantshinkamigotoyohashimototalxn--k7yn9" + + "5exn--karmy-yuaxn--kbrq7oxn--kcrx77d1x4axn--kfjord-iuaxn--klbu-w" + + "oaxn--klt787dxn--kltp7dxn--kltx9axn--klty5xn--3ds443gxn--koluokt" + + "a-7ya57hakubahcavuotnagaraholtaleniwaizumiotsukumiyamazonawsmppl" + + "anetariuminamiizukamiokameokameyamatotakadaxn--kprw13dxn--kpry57" + + "dxn--kpu716fbxosavannahgaxn--kput3is-lostrolekamakurazakiwakunig" + + "amiharustkannamilanotogawaxn--krager-gyatsukanraxn--kranghke-b0a" + + "xn--krdsherad-m8axn--krehamn-dxaxn--krjohka-hwab49jdfastpanelbla" + + "grarchaeologyeongbuk0emmafann-arboretumbriamallamaceiobbcg12038x" + + "n--ksnes-uuaxn--kvfjord-nxaxn--kvitsy-fyatsushiroxn--kvnangen-k0" + + "axn--l-1fairwindsrlxn--l1accentureklamborghinikolaeventsrvareser" + + "vehalflifestylexn--laheadju-7yawaraxn--langevg-jxaxn--lcvr32dxn-" + + "-ldingen-q1axn--leagaviika-52bauhausposts-and-telecommunications" + + "3-us-west-2xn--lesund-huaxn--lgbbat1ad8jelasticbeanstalkhakassia" + + "xn--lgrd-poacctrusteexn--lhppi-xqaxn--linds-pramericanartrvargga" + + "trentoyonakagyokutoyakolobrzegersundxn--lns-qlaquilanstorfjordxn" + + "--loabt-0qaxn--lrdal-sraxn--lrenskog-54axn--lt-liacnpyatigorskod" + + "jeffersonxn--lten-granexn--lury-iraxn--m3ch0j3axn--mely-iraxn--m" + + "erker-kuaxn--mgb2ddestorjdevcloudnshinyoshitomiokamitondabayashi" + + "ogamagoriziaxn--mgb9awbfedorapeoplegnicapebretonamicrosoftbankas" + + "uyanaizulminamiechizenxn--mgba3a3ejtrycloudflareportrevisohughes" + + "omaxn--mgba3a4f16axn--mgba3a4franamizuholdingstpetersburgxn--mgb" + + "a7c0bbn0axn--mgbaakc7dvfedoraprojectransportexn--mgbaam7a8hakuis" + + "-a-greenxn--mgbab2bdxn--mgbah1a3hjkrdxn--mgbai9a5eva00beneventoe" + + "idskoguchikuzenayorovigovtaxihuanflfanfshostrowwlkpmgjovikaratsu" + + "ginamikatagamilitaryonagoyaxn--mgbai9azgqp6jelenia-goraxn--mgbay" + + "h7gpaleoxn--mgbbh1a71exn--mgbc0a9azcgxn--mgbca7dzdoxn--mgberp4a5" + + "d4a87gxn--mgberp4a5d4arxn--mgbgu82axn--mgbi4ecexposedxn--mgbpl2f" + + "hskydivingxn--mgbqly7c0a67fbcnsantabarbaraxn--mgbqly7cvafranzisk" + + "anerimaringatlantakahashimamakiryuohdattorelayxn--mgbt3dhdxn--mg" + + "btf8flatangerxn--mgbtx2bentleyonagunicommbankarelianceu-2xn--mgb" + + "x4cd0abbvieeexn--mix082feiraquarelleaseeklogesaves-the-whalessan" + + "dria-trani-barletta-andriatranibarlettaandriaxn--mix891fermochiz" + + "ukirovogradoyxn--mjndalen-64axn--mk0axin-dslgbtrysiljanxn--mk1bu" + + "44cntoystre-slidrettozawaxn--mkru45is-not-certifiedugit-pagespee" + + "dmobilizeroticanonoichinomiyakexn--mlatvuopmi-s4axn--mli-tlarvik" + + "oryokamikawanehonbetsurutaharaxn--mlselv-iuaxn--moreke-juaxn--mo" + + "ri-qsakuragawaxn--mosjen-eyawatahamaxn--mot-tlavagiskexn--mre-og" + + "-romsdal-qqbuserveexchangexn--msy-ula0hakusanagochijiwadell-ogli" + + "astraderxn--mtta-vrjjat-k7aflakstadaokagakicks-assnasaarlandxn--" + + "muost-0qaxn--mxtq1misawaxn--ngbc5azdxn--ngbe9e0axn--ngbrxn--3e0b" + + "707exn--nit225kosaigawaxn--nmesjevuemie-tcbalsan-sudtirollagdene" + + "snaaseinet-freakstreamswatch-and-clockerxn--nnx388axn--nodessaku" + + "rais-savedunetflixilxn--nqv7fs00emaxn--nry-yla5gxn--ntso0iqx3axn" + + "--ntsq17gxn--nttery-byaeservehttplantsjcbnpparibaselburgxn--nvuo" + + "tna-hwaxn--nyqy26axn--o1acheltenham-radio-openairbusantiquest-a-" + + "la-maisondre-landroidxn--o3cw4haldenxn--o3cyx2axn--od0algxn--od0" + + "aq3beppublishproxyzgorzeleccogladefinimakanegasakiraxn--ogbpf8fl" + + "ekkefjordxn--oppegrd-ixaxn--ostery-fyaxn--osyro-wuaxn--otu796dxn" + + "--p1acferraraxn--p1ais-slickfhappoutwentexn--pbt977collectionxn-" + + "-pgbs0dhlxn--porsgu-sta26ferrarivnexn--pssu33lxn--pssy2uxn--q9jy" + + "b4colognewyorkshirecifedexeterxn--qcka1pmckinseyxn--qqqt11miscon" + + "fusedxn--qxa6axn--qxamuneuestudioxn--rady-iraxn--rdal-poaxn--rde" + + "-ulavangenxn--rdy-0nabaris-uberleetrentino-sudtirolxn--rennesy-v" + + "1axn--rhkkervju-01aferrerotikagoshimalvikaszubyxn--rholt-mragowo" + + "odsidemonmouthalsaitamatsukuris-a-guruslivinghistoryxn--rhqv96gx" + + "n--rht27zxn--rht3dxn--rht61exn--risa-5naturalhistorymuseumcenter" + + "xn--risr-iraxn--rland-uuaxn--rlingen-mxaxn--rmskog-byaxn--rny31h" + + "ammarfeastafricapitalonewmexicodyn-o-saurlandesevenassisicilyxn-" + + "-rovu88beskidyn-ip24xn--rros-granvindafjordxn--rskog-uuaxn--rst-" + + "0naturalsciencesnaturellestudynamisches-dnsokndalxn--rsta-franca" + + "iseharaxn--rvc1e0am3exn--ryken-vuaxn--ryrvik-byaxn--s-1faithamur" + + "akamigoris-a-hard-workersewinbarclaycards3-fips-us-gov-west-1xn-" + + "-s9brj9colonialwilliamsburgroundhandlingroznyxn--sandnessjen-ogb" + + "estbuyshouses3-website-ap-northeast-1xn--sandy-yuaxn--sdtirol-n2" + + "axn--seral-lraxn--ses554gxn--sgne-graphoxn--3hcrj9civilisationis" + + "shinguccircleverappsannaniyodogawaxn--skierv-utazastuff-4-salexn" + + "--skjervy-v1axn--skjk-soaxn--sknit-yqaxn--sknland-fxaxn--slat-5n" + + "aturbruksgymnxn--slt-elabcieszynxn--smla-hraxn--smna-gratangentl" + + "entapisa-geekosakaerodromegallupinbargainstantcloudfunctionswede" + + "nvironmentalconservationfabricafederationionjukudoyamaizuruhrhcl" + + "oudiscourses3-us-east-2xn--snase-nraxn--sndre-land-0cbetainaboxf" + + "usejnymemsettsupportcp4xn--snes-poaxn--snsa-roaxn--sr-aurdal-l8a" + + "xn--sr-fron-q1axn--sr-odal-q1axn--sr-varanger-ggbhzcasinordkappa" + + "lmasfjordenhktjeldsundishakotanhlfanhs3-website-ap-southeast-1xn" + + "--srfold-byaxn--srreisa-q1axn--srum-gratis-a-bulls-fanxn--stfold" + + "-9xaxn--stjrdal-s1axn--stjrdalshalsen-sqbieidsvollimitediskussio" + + "nsbereichaseljeepsondriodejaneirockartuzyoriikariyaltakatorin-th" + + "e-bandain-vpncateringebuildinglassassinationalheritageu-3xn--str" + + "e-toten-zcbielawashingtondclkarlsoyoshiokanzakiyokawaraxn--t60b5" + + "6axn--tckweatherchannelxn--tiq49xqyjeonnamerikawauexn--tjme-hrax" + + "n--tn0agrinetbankoseis-a-painteractivegaskvollxn--tnsberg-q1axn-" + + "-tor131oxn--trany-yuaxn--trentin-sd-tirol-rzbiellaakesvuemielecc" + + "eu-4xn--trentin-sdtirol-7vbrplsbxn--3oq18vl8pn36axn--trentino-sd" + + "-tirol-c3bieszczadygeyachimataipeigersundisrechtrainingleezevje-" + + "og-hornnes3-website-ap-southeast-2xn--trentino-sdtirol-szbievath" + + "letajimabaridagawalbrzycharitydalcesurancechirealmpmnikonanporov" + + "noceanographiquextraspace-to-rentalstomakomaibaraxn--trentinosd-" + + "tirol-rzbifukagawashtenawdev-myqnapcloudeitysfjordivtasvuodnakam" + + "agayahabaghdadivttasvuotnakamuratakahamalselvendrellimoliseminex" + + "n--trentinosdtirol-7vbigv-infoodnetworkangerxn--trentinsd-tirol-" + + "6vbihorologyukincheoninohekinannestadiyukuhashimojindianapolis-a" + + "-bloggerxn--trentinsdtirol-nsbikedaejeonbukcoalvdalaheadjudygarl" + + "andnpalmspringsakerxn--trgstad-r1axn--trna-woaxn--troms-zuaxn--t" + + "ysvr-vraxn--uc0atvaroyxn--uc0ay4axn--uist22handsonyoursidellogli" + + "astradingxn--uisz3gxn--unjrga-rtashkentunesomnarvikommunexn--unu" + + "p4yxn--uuwu58axn--vads-jraxn--valle-aoste-ebbtunkomvuxn--30rr7yx" + + "n--valle-d-aoste-ehbodollstufftoread-booksnesolarssonxn--valleao" + + "ste-e7axn--valledaoste-ebbvacationstuttgartrentinsued-tirolxn--v" + + "ard-jraxn--vegrshei-c0axn--vermgensberater-ctbilbaokinawashirosa" + + "tochigiessensiositelemarkarmoyurihonjournalistjohninomiyakonojor" + + "pelandrangedalinkyard-cloudyclusterxn--vermgensberatung-pwbillus" + + "trationredumbrellahppiacenzachpomorskienirasakindianmarketinglit" + + "chattanooganordlandray-dnsupdaternopilawaweddingliwicexn--vestvg" + + "y-ixa6oxn--vg-yiabkhaziaxn--vgan-qoaxn--vgsy-qoa0jetztrentino-su" + + "ed-tirolxn--vgu402coloradoplateaudioxn--vhquvestfoldxn--vler-qoa" + + "xn--vre-eiker-k8axn--vrggt-xqadxn--vry-yla5gxn--vuq861biocpanama" + + "tta-varjjatjmaxxxboxenapponazure-mobilexn--w4r85el8fhu5dnraxn--w" + + "4rs40lxn--wcvs22dxn--wgbh1columbusheyxn--wgbl6axn--xhq521birdart" + + "centerprisecloudcontrolappleborkdalwaysdatabaseballangenkainanae" + + "robatickets3-website-eu-west-1xn--xkc2al3hye2axn--xkc2dl3a5ee0ha" + + "ngglidingxn--y9a3aquariumishimatsumaebashimodatexn--yer-znaturhi" + + "storischesusakis-gonexn--yfro4i67oxn--ygarden-p1axn--ygbi2ammxn-" + + "-3pxu8koninjambylxn--ystre-slidre-ujbirkenesoddtangenovaranzanqu" + + "anpachigasakihokumakogengerdalaskanittedallasalleangaviikaascoli" + + "picenodumetacentrumeteorappanasonicatholicaxiashorokanaiexn--zbx" + + "025dxn--zf0ao64axn--zf0avxlxn--zfr164birthplacexnbayxz" // nodes is the list of nodes. Each node is represented as a uint32, which // encodes the node's children, wildcard bit and node type (as an index into @@ -524,1809 +526,1818 @@ const text = "9guacuiababia-goracleaningroks-theatree12hpalermomahachijoinvill" // [15 bits] text index // [ 6 bits] text length var nodes = [...]uint32{ - 0x32ce03, - 0x243304, - 0x2d7946, - 0x215803, - 0x215806, - 0x38b3c6, - 0x3ae643, - 0x246d44, - 0x341047, - 0x2d7588, + 0x297a83, + 0x32a504, + 0x2eadc6, + 0x24c943, + 0x24c946, + 0x38b146, + 0x3b05c3, + 0x214bc4, + 0x201507, + 0x2eaa08, 0x1a000c2, - 0x1f3aec7, - 0x377a09, - 0x2c628a, - 0x2c628b, - 0x231b43, - 0x233805, - 0x2203042, - 0x212284, - 0x2d7ac3, - 0x203045, - 0x260c6c2, - 0x3290c3, - 0x2b22c44, - 0x33f285, - 0x2e0c182, - 0x26d6ce, - 0x24e5c3, - 0x3a36c6, - 0x3206082, - 0x2fd2c7, - 0x236086, - 0x3602982, - 0x27f103, - 0x27f104, - 0x397646, - 0x36bf08, - 0x288086, - 0x270104, + 0x1f36987, + 0x376649, + 0x36c4ca, + 0x36c4cb, + 0x201203, + 0x233985, + 0x2201602, + 0x2d2044, + 0x2eaf43, + 0x269045, + 0x2601742, + 0x343083, + 0x2a135c4, + 0x2982c5, + 0x2e0de42, + 0x26e24e, + 0x250b83, + 0x3a6286, + 0x3203082, + 0x306087, + 0x2372c6, + 0x3606bc2, + 0x27f943, + 0x27f944, + 0x399b86, + 0x35bc88, + 0x286046, + 0x26fc84, 0x3a00ac2, - 0x34cb09, - 0x2171c7, - 0x344986, - 0x28dfc9, - 0x32fa48, - 0x34b444, - 0x3947c6, - 0x336a46, - 0x3e03582, - 0x3da686, - 0x24070f, - 0x2112ce, - 0x217bc4, - 0x20d005, - 0x32cd05, - 0x2e1b49, - 0x23b549, - 0x397e47, - 0x3cffc6, - 0x28e143, - 0x4212082, - 0x2232c3, - 0x28da0a, - 0x4613583, - 0x3cea45, - 0x299082, - 0x38c209, - 0x4e02282, - 0x213c04, - 0x21fb46, - 0x2fff45, - 0x36db84, - 0x5643344, - 0x225843, - 0x232b84, - 0x5a03342, - 0x31fd84, - 0x5f8a244, - 0x2fe64a, + 0x34abc9, + 0x2236c7, + 0x202446, + 0x353689, + 0x32f208, + 0x2478c4, + 0x23f2c6, + 0x3c3846, + 0x3e041c2, + 0x36fcc6, + 0x242f4f, + 0x2d108e, + 0x219a44, + 0x218b45, + 0x32a405, + 0x2e7589, + 0x23d709, + 0x39a387, + 0x3ddf06, + 0x267243, + 0x42037c2, + 0x21adc3, + 0x35054a, + 0x460f283, + 0x3d95c5, + 0x29d282, + 0x38b6c9, + 0x4e01182, + 0x201c84, + 0x2f3146, + 0x28a745, + 0x36d1c4, + 0x560fbc4, + 0x220dc3, + 0x232d04, + 0x5a02d02, + 0x235784, + 0x5e79284, + 0x33cb4a, 0x6200882, - 0x21ef47, - 0x27afc8, - 0x7204c82, - 0x2f6e47, - 0x2c2b84, - 0x2c2b87, - 0x3d6805, - 0x362187, - 0x2e73c6, - 0x27d8c4, - 0x328e45, - 0x256407, - 0x8a05802, - 0x3da803, - 0x21e182, - 0x369a03, - 0x8e09bc2, - 0x281705, - 0x9200202, - 0x3c2844, - 0x277445, - 0x217b07, - 0x2fdfce, - 0x2b1044, - 0x261dc4, - 0x20e5c3, - 0x251789, - 0x265f0b, - 0x273788, - 0x28dd88, - 0x2e53c8, - 0x28c008, - 0x34b28a, - 0x362087, - 0x276586, - 0x9615842, - 0x2be403, - 0x3cab03, - 0x3cd244, - 0x2be443, - 0x28ca83, - 0x1736f42, - 0x9a019c2, - 0x27e945, - 0x313dc6, - 0x2335c4, - 0x379907, - 0x263e46, - 0x2bfa04, - 0x399647, - 0x2019c3, - 0x9ecb4c2, - 0xa227682, - 0xa627442, - 0x227446, - 0xaa00282, - 0x285845, - 0x338483, - 0x3bfc44, - 0x2eddc4, - 0x2eddc5, - 0x3c7543, - 0xae48343, - 0xb338dc2, - 0x203c05, - 0x203c0b, - 0x20b24b, - 0x26bb44, - 0x204a09, - 0x205f44, - 0xb606802, - 0x207043, - 0x207183, - 0xba08082, - 0x2ed8ca, - 0xbe08342, - 0x212505, - 0x2de9ca, - 0x35cc04, - 0x208343, - 0x209ec4, - 0x20ba03, - 0x20ba04, - 0x20ba07, - 0x20c585, - 0x20d346, - 0x213006, - 0x213cc3, - 0x217f48, - 0x20db43, - 0xc209582, - 0x23d4c8, - 0x20958b, - 0x221cc8, - 0x222a86, - 0x224447, - 0x226fc8, - 0xd205b82, - 0xd6c1142, - 0x33f3c8, - 0x20f9c7, - 0x30f645, - 0x30f648, - 0xdadcf48, - 0x27ff43, - 0x22a104, - 0x38b442, - 0xde2a542, - 0xe243bc2, - 0xea2a8c2, - 0x22a8c3, - 0xee04042, - 0x30e303, - 0x237484, - 0x204043, - 0x206444, - 0x37454b, - 0x2094c3, - 0x2e94c6, - 0x27f404, - 0x2ba20e, - 0x381e45, - 0x3a37c8, - 0x3dd347, - 0x3dd34a, - 0x22f603, - 0x243107, - 0x2660c5, - 0x22f604, - 0x250206, - 0x250207, - 0x2fc304, - 0xf30f084, - 0x2fe304, - 0x2fe306, - 0x3db9c4, - 0x3ba486, - 0x226e03, - 0x3a8908, - 0x3c38c8, - 0x291d83, - 0x2ed883, - 0x346ac4, - 0x358183, - 0xfa09382, - 0xfe8b742, - 0x20b983, - 0x240d86, - 0x329383, - 0x35b7c4, - 0x102179c2, - 0x24a583, - 0x2179c3, - 0x214c82, - 0x10600d42, - 0x2c5c86, - 0x2344c7, - 0x2f8407, - 0x3a9405, - 0x207484, - 0x29bac5, - 0x267347, - 0x3cb009, - 0x2db306, - 0x2ea9c6, - 0x10a02c82, - 0x331448, - 0x31f486, - 0x34ebc5, - 0x3ac387, - 0x306104, - 0x306105, - 0x10e02c84, - 0x202c88, - 0x11203cc2, - 0x11600482, - 0x21d746, + 0x3c1f47, + 0x2d0548, + 0x76031c2, + 0x328287, + 0x2c9044, + 0x2c9047, + 0x3d57c5, + 0x378847, + 0x303c06, + 0x2f0e44, + 0x342e05, + 0x257187, + 0x8e01482, + 0x36fe43, + 0x9226782, + 0x3633c3, + 0x9606b42, + 0x274985, + 0x9a00202, + 0x2cd104, + 0x2c23c5, + 0x219987, + 0x249e0e, + 0x2b6e44, + 0x290f44, + 0x210603, + 0x286ac9, + 0x3aa74b, + 0x2edac8, + 0x303148, + 0x3b1888, + 0x3d9ac8, + 0x3534ca, + 0x378747, + 0x2cdf46, + 0x9e47402, + 0x374d83, + 0x3ccac3, + 0x3ce604, + 0x374dc3, + 0x35cb83, + 0x1732182, + 0xa2016c2, + 0x27cd05, + 0x224686, + 0x233744, + 0x38a5c7, + 0x2355c6, + 0x2c8984, + 0x3abfc7, + 0x215dc3, + 0xa6d5bc2, + 0xaa20f82, + 0xae20d42, + 0x220d46, + 0xb200282, + 0x284405, + 0x3336c3, + 0x3c8744, + 0x2f7784, + 0x2f7785, + 0x3d6d83, + 0xb602703, + 0xba019c2, + 0x205fc5, + 0x205fcb, + 0x20ec0b, + 0x229904, + 0x206689, + 0x208244, + 0xbe09c42, + 0x20a483, + 0x20a703, + 0xc202e82, + 0x398a0a, + 0xc601542, + 0x2d22c5, + 0x2e6a0a, + 0x247584, + 0x20b103, + 0x20b7c4, + 0x20d6c3, + 0x20d6c4, + 0x20d6c7, + 0x20e245, + 0x2114c6, + 0x211846, + 0x2124c3, + 0x217688, + 0x208f03, + 0xca0cd42, + 0x308648, + 0x2862cb, + 0x21ffc8, + 0x2205c6, + 0x2213c7, + 0x227208, + 0xda07682, + 0xde1d482, + 0x298408, + 0x210c07, + 0x30dcc5, + 0x30dcc8, + 0xe301108, + 0x26c243, + 0x22a444, + 0x38b1c2, + 0xe62a882, + 0xea16182, + 0xf22c042, + 0x22c043, + 0xf6086c2, + 0x296303, + 0x3b2744, + 0x2086c3, + 0x247884, + 0x296a4b, + 0x215843, + 0x2f1486, + 0x278704, + 0x2c340e, + 0x38f345, + 0x261e48, + 0x3a6387, + 0x3a638a, + 0x22f983, + 0x2343c7, + 0x3aa905, + 0x22f984, + 0x2526c6, + 0x2526c7, + 0x31a204, + 0xfb0d704, + 0x24a144, + 0x33c806, + 0x22b844, + 0x3b5cc6, + 0x232443, + 0x3ba348, + 0x3df888, + 0x290f03, + 0x3989c3, + 0x340384, + 0x355943, + 0x10215702, + 0x1068d502, + 0x218043, + 0x2435c6, + 0x343343, + 0x30c504, + 0x10a3fec2, + 0x24cf43, + 0x327783, + 0x212c02, + 0x10e00d42, + 0x2cb886, + 0x234807, + 0x3c25c7, + 0x3b91c5, + 0x3d3004, + 0x29fbc5, + 0x2253c7, + 0x2ade49, + 0x2c19c6, + 0x2ec246, + 0x1120b682, + 0x2f4b48, + 0x3ae1c6, + 0x2aed85, + 0x30a6c7, + 0x3562c4, + 0x3562c5, + 0x11668c84, + 0x268c88, + 0x11a06082, + 0x11e00482, + 0x26e986, 0x200488, - 0x335f85, - 0x34d406, - 0x351b08, - 0x35b088, - 0x11a07d45, - 0x11e25744, - 0x322d47, - 0x122059c2, - 0x1268cac2, - 0x13a0c302, - 0x21fc45, - 0x284a05, - 0x384006, - 0x326507, - 0x3a80c7, - 0x1422c0c3, - 0x318887, - 0x3a4548, - 0x1f22c289, - 0x26d887, - 0x22c9c7, - 0x22d408, - 0x22dc06, - 0x22f106, - 0x23000c, - 0x230d0a, - 0x231b87, - 0x2336cb, - 0x234307, - 0x23430e, - 0x1f635404, - 0x235604, - 0x237347, - 0x25bfc7, - 0x23ac06, - 0x23ac07, - 0x333e47, - 0x2e4003, - 0x1fa2ae02, - 0x23bec6, - 0x23beca, - 0x23c90b, - 0x23e487, - 0x23ef05, - 0x23f443, - 0x23f946, - 0x23f947, - 0x2ef083, - 0x1fe00102, - 0x24038a, - 0x20378f82, - 0x20661482, - 0x20a3d1c2, - 0x20e36182, - 0x242505, - 0x242cc4, - 0x21659dc2, - 0x31fe05, - 0x23cf03, - 0x2954c5, - 0x2028c4, - 0x20a204, - 0x280186, - 0x27e0c6, - 0x203e03, - 0x3bcfc4, - 0x2f8703, - 0x226081c2, - 0x2247c4, - 0x3232c6, - 0x2247c5, - 0x244086, - 0x3ac488, - 0x22b144, - 0x36b888, - 0x322805, - 0x37f488, - 0x2c24c6, - 0x3049c7, - 0x287804, - 0x23a87806, - 0x23ee85c3, - 0x39c943, - 0x2ec108, - 0x331344, - 0x24361707, - 0x24abe846, - 0x2dbb09, - 0x330048, - 0x34b8c8, - 0x355644, - 0x3c6d83, - 0x23cfc2, - 0x24e4cfc2, - 0x25201d42, - 0x204583, - 0x2560a782, - 0x2ef004, - 0x24ad06, - 0x21af83, - 0x2b6387, - 0x2f7443, - 0x334888, - 0x2101c5, - 0x259203, - 0x2773c5, - 0x277504, - 0x305e06, - 0x2127c6, - 0x217a46, - 0x2203c4, - 0x2346c3, - 0x25a05202, - 0x25e2ec05, + 0x331ac5, + 0x34b646, + 0x34ef88, + 0x35b788, + 0x12201805, + 0x126136c4, + 0x2136c7, + 0x12a07cc2, + 0x12e167c2, + 0x14201242, + 0x2f3245, + 0x14a83545, + 0x262486, + 0x323647, + 0x39f087, + 0x14e14a83, + 0x338487, + 0x38a948, + 0x2022cd09, + 0x26e407, + 0x22d447, + 0x22e548, + 0x22ed46, + 0x22f486, + 0x2300cc, + 0x23180a, + 0x231c07, + 0x23384b, + 0x234647, + 0x23464e, + 0x20635944, + 0x235b44, + 0x238b07, + 0x25c7c7, + 0x23d006, + 0x23d007, + 0x3b3147, + 0x2d2c43, + 0x20a2ba02, + 0x23e306, + 0x23e30a, + 0x23f44b, + 0x240987, + 0x241405, + 0x241e43, + 0x242246, + 0x242247, + 0x2f8983, + 0x20e00102, + 0x242bca, + 0x21377dc2, + 0x2173da82, + 0x21a3fd02, + 0x21e373c2, + 0x245385, + 0x245d44, + 0x22a05582, + 0x235805, + 0x23fa43, + 0x314885, + 0x2688c4, + 0x2afb04, + 0x2cea06, + 0x250f06, + 0x2061c3, + 0x3bb644, + 0x303ec3, + 0x23a02a42, + 0x213c44, + 0x213c46, + 0x221745, + 0x244d46, + 0x30a7c8, + 0x223dc4, + 0x367bc8, + 0x231e85, + 0x262b88, + 0x2caa06, + 0x217c07, + 0x273504, + 0x24e73506, + 0x252239c3, + 0x39e183, + 0x31d988, + 0x29ffc4, + 0x2572ccc7, + 0x25ee4846, + 0x2e4849, + 0x362008, + 0x36a408, + 0x3b6544, + 0x3c7903, + 0x22dd42, + 0x2624e782, + 0x2660fa82, + 0x3c9083, + 0x26a01642, + 0x2f8904, + 0x279986, + 0x21c103, + 0x2bc7c7, + 0x303743, + 0x32fcc8, + 0x20b885, + 0x25a683, + 0x2c2345, + 0x2c2484, + 0x30bcc6, + 0x20cac6, + 0x2198c6, + 0x2f39c4, + 0x234a03, + 0x26e0fe02, + 0x27233fc5, 0x200843, - 0x2660f4c2, - 0x22c243, - 0x373605, - 0x26a32c43, - 0x27232c49, - 0x27600942, - 0x27e04282, - 0x28b045, - 0x215e46, - 0x205606, - 0x2cf508, - 0x2cf50b, - 0x32ed0b, - 0x3a9605, - 0x2cbc09, - 0x1600b42, - 0x2cfc08, - 0x204d04, - 0x28601bc2, - 0x34a603, - 0x28e5c186, - 0x33e208, - 0x29201a02, - 0x28c608, - 0x29609802, - 0x33c4ca, - 0x29a46e03, - 0x2a378046, - 0x3910c8, - 0x330906, - 0x387087, - 0x240907, - 0x3365ca, - 0x35cc84, - 0x35fe04, - 0x376889, - 0x2a7a7545, - 0x2114c6, - 0x20fbc3, - 0x24bd04, - 0x2aa0d644, - 0x344147, - 0x2aee3587, - 0x293104, - 0x236cc5, - 0x3840c8, - 0x3a03c7, - 0x243547, - 0x2b20c202, - 0x298d44, - 0x294348, - 0x2443c4, - 0x249204, - 0x249b85, - 0x249cc7, - 0x2b658549, - 0x24a804, - 0x24b0c9, - 0x24b308, - 0x24ba84, - 0x24ba87, - 0x2ba4cdc3, - 0x24d2c7, - 0x2be014c2, - 0x16b1b82, - 0x24df86, - 0x24e607, - 0x24e884, - 0x24f687, - 0x250647, - 0x2510c3, - 0x2b12c2, - 0x20bcc2, - 0x28de83, - 0x3be3c4, - 0x3be3cb, - 0x2c28de88, - 0x258bc4, - 0x254205, - 0x255c47, - 0x238a05, - 0x2d908a, - 0x258b03, - 0x2c603d42, - 0x20da44, - 0x25bd89, - 0x2601c3, - 0x260287, - 0x2683c9, - 0x3de348, - 0x23e2c3, - 0x27c387, - 0x27ce49, - 0x266883, - 0x284fc4, - 0x286209, - 0x289406, - 0x2c7d43, - 0x2076c2, - 0x235c83, - 0x2b1987, - 0x235c85, - 0x3b8806, - 0x26e144, - 0x3cc645, - 0x279803, + 0x27a07382, + 0x22d1c3, + 0x2676c5, + 0x27e32dc3, + 0x28632dc9, + 0x28a00942, + 0x29208902, + 0x28ce05, 0x213f06, - 0x210dc3, - 0x204c02, - 0x248304, - 0x2ca6bc02, - 0x2ce6bc03, - 0x2d2020c2, - 0x247603, - 0x213484, - 0x239bc7, - 0x216586, - 0x278042, - 0x2d65c582, - 0x3ac684, - 0x2da0bb82, - 0x2de063c2, - 0x2b36c4, - 0x2b36c5, - 0x27d545, - 0x366a06, - 0x2e204882, - 0x3bd645, - 0x3cedc5, - 0x204883, - 0x21a286, - 0x21b845, - 0x2273c2, - 0x35acc5, - 0x2273c4, - 0x22b083, - 0x22b2c3, - 0x2e61d302, - 0x256607, - 0x24b504, - 0x24b509, - 0x24bc04, - 0x284883, - 0x39bf88, - 0x2ea84884, - 0x284886, - 0x2a6b43, - 0x254c43, - 0x228b03, - 0x2eeedc82, - 0x302342, - 0x2f200642, - 0x339f48, - 0x301408, - 0x3aedc6, - 0x272945, - 0x2802c5, - 0x345387, - 0x2f677f05, - 0x220482, - 0x2fa97642, - 0x2fe00042, - 0x278cc8, - 0x31f3c5, - 0x2f3e44, - 0x243fc5, - 0x245547, - 0x27a1c4, - 0x240282, - 0x30205702, - 0x352784, - 0x222f47, - 0x28cf47, - 0x362144, - 0x3cc143, - 0x291cc4, - 0x291cc8, - 0x22f446, - 0x25008a, - 0x2eb544, - 0x296008, - 0x242ec4, - 0x224546, - 0x297604, - 0x21ff46, - 0x24b7c9, - 0x2a62c7, - 0x2087c3, - 0x306033c2, - 0x34b643, - 0x206a02, - 0x30a17d82, - 0x2fb0c6, - 0x380708, - 0x2a8787, - 0x26ad49, - 0x2ad689, - 0x2aa9c5, - 0x2abd49, - 0x2ac545, - 0x2ad385, - 0x2ae008, - 0x30e04104, - 0x31251207, - 0x22cd83, - 0x2ae207, - 0x22cd86, - 0x2ae607, - 0x2a5e45, - 0x22c603, - 0x31630ac2, - 0x208584, - 0x31a0adc2, - 0x31e04742, - 0x3ae186, - 0x27af45, - 0x2b0587, - 0x2fef43, - 0x28ca04, - 0x201e83, - 0x20f703, - 0x32203dc2, - 0x32a01cc2, - 0x38b4c4, - 0x3881c3, - 0x2fbf45, - 0x32e00f42, - 0x33602b82, - 0x2d5c86, - 0x2fdf04, - 0x303f04, - 0x303f0a, - 0x33e005c2, - 0x263f43, - 0x20cd0a, - 0x214388, - 0x34224e44, + 0x28ec06, + 0x2e6608, + 0x2e660b, + 0x339c8b, + 0x3b93c5, + 0x2d6149, + 0x1600b42, + 0x2f0548, + 0x206984, + 0x29a03c42, + 0x34a843, + 0x2a25c986, + 0x3c2888, + 0x2a6142c2, + 0x35c708, + 0x2aaaac82, + 0x337f8a, + 0x2aedb383, + 0x2b776c86, + 0x392488, + 0x214886, + 0x387b87, + 0x243147, + 0x3c33ca, + 0x247604, + 0x360704, + 0x376209, + 0x2bba9dc5, + 0x26e286, + 0x210e03, + 0x24e3c4, + 0x2be196c4, + 0x3458c7, + 0x2c241c87, + 0x294f84, + 0x39f545, + 0x262548, + 0x39e647, + 0x3a24c7, + 0x2c60dec2, + 0x29cf44, + 0x293048, + 0x246d84, + 0x24b904, + 0x24bcc5, + 0x24be07, + 0x2ca7ebc9, + 0x2232c4, + 0x24d789, + 0x24d9c8, + 0x24e144, + 0x24e147, + 0x2ce4e583, + 0x24ea87, + 0x2d20bb42, + 0x16b8842, + 0x24fa46, + 0x250087, + 0x250704, + 0x251d07, + 0x253787, + 0x253f83, + 0x22dec2, + 0x20d982, + 0x303243, + 0x3c6704, + 0x3c670b, + 0x2d703248, + 0x25a044, + 0x255b85, + 0x257407, + 0x2e92c5, + 0x33144a, + 0x259f83, + 0x2da05dc2, + 0x208e04, + 0x25c589, + 0x260c03, + 0x260cc7, + 0x240749, + 0x205dc8, + 0x22af03, + 0x27b3c7, + 0x27be89, + 0x225583, + 0x283b84, + 0x284d09, + 0x28b2c6, + 0x2f4103, + 0x2015c2, + 0x23c903, + 0x2b8647, + 0x23c905, + 0x3b1686, + 0x270744, + 0x35ff85, + 0x27c7c3, + 0x212706, + 0x292503, + 0x206882, + 0x248f84, + 0x2de299c2, + 0x2e2299c3, + 0x2e607082, + 0x248343, + 0x211cc4, + 0x2ece07, + 0x2946c6, + 0x262302, + 0x2ea5cd82, + 0x30a9c4, + 0x2f20d842, + 0x2f616902, + 0x2ef084, + 0x2ef085, + 0x302c85, + 0x35ef86, + 0x2fa0f582, + 0x39b745, + 0x3ba745, + 0x283483, + 0x20f586, + 0x20fec5, + 0x220cc2, + 0x35b3c5, + 0x220cc4, + 0x223d03, + 0x223f43, + 0x2fe05b42, + 0x2e29c7, + 0x24dbc4, + 0x24dbc9, + 0x24e2c4, + 0x2833c3, + 0x2b61c8, + 0x302833c4, + 0x2833c6, + 0x2a37c3, + 0x256303, + 0x308003, + 0x306f7642, + 0x309442, + 0x30a00642, + 0x335408, + 0x36af48, + 0x3b7906, + 0x3830c5, + 0x22c805, + 0x204287, + 0x30e77185, + 0x23c782, + 0x3129b602, + 0x31600042, + 0x2cfb88, + 0x3ae105, + 0x2fc7c4, + 0x244c85, + 0x2547c7, + 0x3a3884, + 0x242ac2, + 0x31a11442, + 0x351144, + 0x220a87, + 0x28ddc7, + 0x378804, + 0x3cd483, + 0x290e44, + 0x290e48, + 0x22f7c6, + 0x25254a, + 0x326584, + 0x299288, + 0x234184, + 0x2214c6, + 0x29b5c4, + 0x2f3546, + 0x24de89, + 0x2a9fc7, + 0x207543, + 0x31e3ee42, + 0x3b62c3, + 0x209e42, + 0x32204702, + 0x349e46, + 0x381988, + 0x2abfc7, + 0x228b09, + 0x2b1549, + 0x2ad505, + 0x2afc09, + 0x2b0405, + 0x2b1245, + 0x2b1f88, + 0x32608784, + 0x32a540c7, + 0x22d803, + 0x2b2187, + 0x22d806, + 0x2b25c7, + 0x2a9ac5, + 0x22d083, + 0x32e315c2, + 0x20b344, + 0x3320e782, + 0x33606502, + 0x380e86, + 0x2d04c5, + 0x2b54c7, + 0x343a03, + 0x35cb04, + 0x209283, + 0x2cd743, + 0x33a06182, + 0x34205bc2, + 0x38b244, + 0x22de83, + 0x3047c5, + 0x34600f42, + 0x34e01f02, + 0x304fc6, + 0x201f04, + 0x306bc4, + 0x306bca, + 0x356005c2, + 0x213903, + 0x21884a, + 0x21bac8, + 0x35a21dc4, 0x2005c3, - 0x34601803, - 0x266ac9, - 0x24d8c9, - 0x2b6486, - 0x34a14543, - 0x36f705, - 0x3b62cd, - 0x214546, - 0x219e4b, - 0x34e129c2, - 0x394608, - 0x38218042, - 0x38604dc2, - 0x2b3905, - 0x38a01742, - 0x2c67c7, - 0x214903, - 0x21ba08, - 0x38e02cc2, - 0x219384, - 0x20ff03, - 0x2f7ac5, - 0x23d006, - 0x21e244, - 0x2ed843, - 0x2b26c3, - 0x392163c2, - 0x3a9584, - 0x3b77c5, - 0x2b1587, - 0x279c43, - 0x2b2183, - 0x16b2242, - 0x2b2243, - 0x2b2643, - 0x39600e02, - 0x246b84, - 0x27e2c6, - 0x3cba43, - 0x2b2d43, - 0x39a48902, - 0x248908, - 0x2b3d84, - 0x20ed06, - 0x255087, - 0x270906, - 0x291e84, - 0x47e01b82, - 0x22cc4b, - 0x2f91ce, - 0x216c0f, - 0x292e43, - 0x48659902, - 0x163ea82, - 0x48a017c2, - 0x296583, - 0x20e883, - 0x2dd4c6, - 0x3cb286, - 0x2b0187, - 0x30b0c4, - 0x48e11902, - 0x492106c2, - 0x245005, - 0x2f1887, - 0x2b47c6, - 0x496526c2, - 0x2526c4, - 0x2b93c3, - 0x49a4e082, - 0x49f72383, - 0x2bac04, - 0x2c1d89, - 0x4a2c8c82, - 0x4a601882, - 0x201885, - 0x4aac9182, - 0x4ae03c42, - 0x35f107, - 0x377c8b, - 0x2406c5, - 0x2570c9, - 0x268746, - 0x4b207844, - 0x328949, - 0x2c9cc7, - 0x32a547, - 0x22abc3, - 0x2b3546, - 0x3246c7, - 0x20a443, - 0x291246, - 0x4ba23342, - 0x4be1d702, - 0x34b783, - 0x38c3c5, - 0x221587, - 0x3cb386, - 0x235c05, - 0x24b484, - 0x2a4d05, - 0x38cf44, - 0x4c201b02, - 0x2c71c4, - 0x267f44, - 0x38830d, - 0x37adc9, - 0x22aec8, - 0x201b04, - 0x3dad85, - 0x3a8e87, - 0x206504, - 0x263f07, - 0x2eb205, - 0x4c607b04, - 0x2a8b45, - 0x25ee84, - 0x27a306, - 0x35f885, - 0x4ca26902, - 0x21d6c3, - 0x28f783, - 0x348084, - 0x348085, - 0x37c586, - 0x235d45, - 0x3d3284, - 0x32c043, - 0x4ce0a6c6, - 0x225045, - 0x225c85, - 0x326404, - 0x2eb5c3, - 0x2eb5cc, - 0x4d204482, - 0x4d601442, - 0x4da03102, - 0x20e403, - 0x20e404, - 0x4de05f82, - 0x380d88, - 0x3b88c5, - 0x2c93c4, - 0x23aa86, - 0x4e217002, - 0x4e6115c2, - 0x4ea00c42, - 0x291a85, - 0x220286, - 0x20d584, - 0x397b86, - 0x21ed06, - 0x221983, - 0x4ee9e10a, - 0x279e05, - 0x28d9c3, - 0x2254c6, - 0x3bd449, - 0x2254c7, - 0x2a9c48, - 0x32f909, - 0x3b9e48, - 0x303706, - 0x20e583, - 0x4f21fc02, - 0x39dc88, - 0x4f644502, - 0x4fa06a42, - 0x238cc3, - 0x2e2a45, - 0x29b404, - 0x2f5d89, - 0x32acc4, - 0x3dabc8, - 0x50206a43, - 0x507749c4, - 0x215e88, - 0x388247, - 0x50a52742, - 0x22e302, - 0x32cc85, - 0x261b89, - 0x211543, - 0x27fcc4, - 0x36f6c4, - 0x20e903, - 0x2812ca, - 0x50f40d82, - 0x512083c2, - 0x2cb443, - 0x38f5c3, - 0x162c142, - 0x2bdc03, - 0x5161d902, - 0x51a00bc2, - 0x51f03f84, - 0x3b3506, - 0x269884, - 0x278b03, - 0x3bf203, - 0x52200bc3, - 0x23cc86, - 0x3a0e45, - 0x2cb5c7, - 0x2cf7c6, - 0x2d0648, - 0x2d0846, - 0x2035c4, - 0x29cd0b, - 0x2d3643, - 0x2d3645, - 0x21fdc2, - 0x35f402, - 0x52642582, - 0x52a05a02, - 0x215fc3, - 0x52e6bf42, - 0x26bf43, - 0x2d46c3, - 0x5360cac2, - 0x53ad9bc6, - 0x257906, - 0x53ed9d02, - 0x542071c2, - 0x5462b302, - 0x54a09082, - 0x54e18942, - 0x552050c2, - 0x208b03, - 0x26cb45, - 0x379b06, - 0x55617b84, - 0x3230ca, - 0x3a5d46, - 0x20bdc4, - 0x28dd43, - 0x56212b02, - 0x205642, - 0x22c203, - 0x5660a803, - 0x3b8307, - 0x35f787, - 0x58ae4447, - 0x39e847, - 0x229183, - 0x333b4a, - 0x340644, - 0x319084, - 0x31908a, - 0x3a8205, - 0x58e11482, - 0x24df43, - 0x59200602, - 0x24bbc3, - 0x34b603, - 0x59a00582, - 0x3a44c4, - 0x345584, - 0x3b0645, - 0x31e4c5, - 0x2e4a06, - 0x304146, - 0x59e39242, - 0x5a202f42, - 0x33d185, - 0x257612, - 0x353286, - 0x270e03, - 0x356606, - 0x31cd05, - 0x16045c2, - 0x626080c2, - 0x376203, - 0x2080c3, - 0x396203, - 0x62a18d42, - 0x23a183, - 0x63223242, - 0x220103, - 0x300808, - 0x239503, - 0x239506, - 0x3c4d87, - 0x321186, - 0x32118b, - 0x20bd07, - 0x2ebf04, - 0x63a00c02, - 0x3b8745, - 0x63e09783, - 0x21d283, - 0x2e60c5, - 0x333a43, - 0x64733a46, - 0x3c8fca, - 0x2a3fc3, - 0x235f44, - 0x2003c6, - 0x34efc6, - 0x64a16603, - 0x340007, - 0x2669c7, - 0x29e985, - 0x26f486, - 0x2158c3, - 0x6761a4c3, - 0x67a00a82, - 0x67e8f804, - 0x3c36c9, - 0x2137c5, - 0x229bc4, - 0x354e88, - 0x2e47c5, - 0x682352c5, - 0x23f549, - 0x344a43, - 0x261404, - 0x686161c2, - 0x2161c3, - 0x68a74542, - 0x274546, - 0x1678002, - 0x68e08f82, - 0x291988, - 0x291c83, - 0x2a8a87, - 0x2b2745, - 0x2b22c5, - 0x2b22cb, - 0x2e8206, - 0x2b24c6, - 0x23bb44, - 0x2e8946, - 0x69321408, - 0x27f4c3, - 0x264503, - 0x264504, - 0x2e51c4, - 0x2ea707, - 0x2ec545, - 0x696ec682, - 0x69a08242, - 0x6a21ae45, - 0x2b8f44, - 0x2d244b, - 0x2edcc8, - 0x250f44, - 0x6a62ad42, - 0x6aa23c42, - 0x3ba403, - 0x2efb84, - 0x2efe45, - 0x2f0607, - 0x2f3984, - 0x362244, - 0x6ae16102, - 0x37b5c9, - 0x2f4c05, - 0x240985, - 0x2f5cc5, - 0x6b216103, - 0x2f67c4, - 0x2f67cb, - 0x2f8a84, - 0x2f8d4b, - 0x2f95c5, - 0x216d4a, - 0x2f9e88, - 0x2fa08a, - 0x2fa883, - 0x2fa88a, - 0x6ba13602, - 0x6be20082, - 0x6c2ba0c3, - 0x6c6fdb02, - 0x2fdb03, - 0x6caed182, - 0x6cf38c02, - 0x301f04, - 0x218086, - 0x3978c5, - 0x303c03, - 0x32d3c6, + 0x35e96b43, + 0x237909, + 0x22e0c9, + 0x2bc8c6, + 0x3621bc83, + 0x21bc85, + 0x222f8d, + 0x226586, + 0x26518b, + 0x3660ccc2, + 0x205708, + 0x3a217782, + 0x3a605382, + 0x2bad85, + 0x3aa04582, + 0x2b3307, + 0x210083, + 0x210088, + 0x3ae07882, + 0x288304, + 0x20c743, + 0x33b805, + 0x23fb46, + 0x224004, + 0x398983, + 0x2b9583, + 0x3b201d82, + 0x3b9344, + 0x3d4c45, + 0x2b8247, + 0x279403, + 0x2b8e43, + 0x16b9102, + 0x2b9103, + 0x2b9503, + 0x3b600e02, + 0x3473c4, + 0x251106, + 0x2e42c3, + 0x2b9c03, + 0x3ba49582, + 0x249588, + 0x2bab84, + 0x347146, + 0x255707, + 0x284646, + 0x29ff44, + 0x49e03fc2, + 0x22d6cb, + 0x2ff50e, + 0x216d8f, + 0x39d6c3, + 0x4a65ac42, + 0x161fb02, + 0x4aa0af02, + 0x2928c3, + 0x2108c3, + 0x20af06, + 0x21d306, + 0x34dec7, + 0x310c44, + 0x4ae14042, + 0x4b20bd82, + 0x2e0685, + 0x2ff987, + 0x2bb206, + 0x4b662702, + 0x384c44, + 0x2c03c3, + 0x4ba01e42, + 0x4bf73103, + 0x2c2984, + 0x2c8009, + 0x4c2ced42, + 0x4c614d42, + 0x344945, + 0x4cad3942, + 0x4ce06002, + 0x35f947, + 0x3768cb, + 0x242f05, + 0x258109, + 0x26aa86, + 0x4d209504, + 0x295449, + 0x2d46c7, + 0x3dea87, + 0x22c343, + 0x2eef06, + 0x324047, + 0x25cc03, + 0x2a6a86, + 0x4da1ae42, + 0x4de33042, + 0x3b6403, + 0x38b885, + 0x21f407, + 0x236146, + 0x23c885, + 0x24db44, + 0x2a8985, + 0x38dac4, + 0x4e202482, + 0x2cc844, + 0x22dfc4, + 0x22dfcd, + 0x377189, + 0x22c648, + 0x344bc4, + 0x328845, + 0x3b8c47, + 0x3c5cc4, + 0x265907, + 0x2e4005, + 0x4e6ac604, + 0x2bf345, + 0x25f8c4, + 0x3a39c6, 0x3973c5, - 0x3d2dc4, - 0x6d200902, - 0x29fc84, - 0x2cb88a, - 0x3001c7, - 0x32a006, - 0x242f47, - 0x23bf03, - 0x2bac48, - 0x3c608b, - 0x2b6585, - 0x2c26c5, - 0x2c26c6, - 0x229984, - 0x3a4f48, - 0x20f883, - 0x25b984, - 0x336947, - 0x2ebb46, - 0x340846, - 0x2ba04a, - 0x24b144, - 0x31b14a, - 0x6d7009c6, - 0x3009c7, - 0x254287, - 0x273f04, - 0x273f09, - 0x251e05, - 0x234f8b, - 0x2ed083, - 0x212983, - 0x6da1de03, - 0x331d84, - 0x6de00682, - 0x228906, - 0x6e2bb4c5, - 0x356845, - 0x24e1c6, - 0x2a1384, - 0x6e602442, - 0x23f484, - 0x6ea0a982, - 0x3287c5, - 0x34c884, - 0x6f61b443, - 0x6fa08102, - 0x208103, - 0x3062c6, - 0x6fe04e82, - 0x392248, - 0x225344, - 0x225346, - 0x38fe46, - 0x70255d04, - 0x20a645, - 0x225648, - 0x227187, - 0x34e087, - 0x34e08f, - 0x294246, - 0x23b743, - 0x23fac4, - 0x20dc83, - 0x224684, - 0x24e784, - 0x706085c2, - 0x28b443, - 0x335543, - 0x70a09482, - 0x209483, - 0x227603, - 0x20c60a, - 0x272bc7, - 0x25398c, - 0x70e53c46, - 0x253dc6, - 0x254d87, - 0x7122d847, - 0x25aac9, - 0x23d604, - 0x71660404, - 0x71a16002, - 0x71e02e42, - 0x2ba406, - 0x33fe04, - 0x28b8c6, - 0x22dcc8, - 0x38c484, - 0x2d7b46, - 0x2055c5, - 0x7228a748, - 0x23fa43, - 0x314705, - 0x28dc43, - 0x240a83, - 0x240a84, - 0x20da03, - 0x72648d42, - 0x72a03382, - 0x2ecf49, - 0x291b85, - 0x292544, - 0x296b45, - 0x209b04, - 0x2cd147, - 0x35a545, - 0x72e46484, - 0x2d2088, - 0x2d2f86, - 0x2dedc4, - 0x2e13c8, - 0x2e1a07, - 0x73201702, - 0x2e99c4, - 0x310d44, - 0x2c2d87, - 0x73605bc4, - 0x215782, - 0x73a01782, - 0x201783, - 0x201784, - 0x29f703, - 0x2aed05, - 0x73e2e942, - 0x302245, - 0x287582, - 0x30a205, - 0x3c0085, - 0x74210342, - 0x217944, - 0x74602602, - 0x28eb86, - 0x2bf706, - 0x261cc8, - 0x2c3748, - 0x3ae104, - 0x30ed05, - 0x3abbc9, - 0x2cfd44, - 0x3c8f84, - 0x2204c3, - 0x319c83, - 0x74b19c85, - 0x2411c5, - 0x284b04, - 0x356bcd, - 0x293042, - 0x359103, - 0x74e09442, - 0x75203a42, - 0x391d05, - 0x3babc7, - 0x21e484, - 0x32fb09, - 0x2cb9c9, - 0x277e43, - 0x277e48, - 0x245e09, - 0x214947, - 0x204185, - 0x37c106, - 0x37ec86, - 0x3808c5, - 0x37aec5, - 0x75601a82, - 0x287205, - 0x2b7748, - 0x2c5a46, - 0x75a52b07, - 0x2bd2c4, - 0x2fc647, - 0x305546, - 0x75e01082, - 0x37c286, - 0x30988a, - 0x30a105, - 0x762e8f82, - 0x76621902, - 0x3645c6, - 0x221908, - 0x76a8d107, - 0x76e43b02, - 0x288ec3, - 0x2ff806, - 0x226884, - 0x275b06, - 0x319f46, - 0x2034ca, - 0x2021c5, - 0x3006c6, - 0x2520c3, - 0x2520c4, - 0x207442, - 0x331403, - 0x7720e442, - 0x2f1803, - 0x7760cf84, - 0x221a44, - 0x77a21a4a, - 0x22ce03, - 0x266c87, - 0x30d106, - 0x2ff144, - 0x20bc82, - 0x2a6f02, - 0x77e007c2, - 0x22b9c3, - 0x254047, + 0x4ea05442, + 0x26e903, + 0x267fc3, + 0x348cc4, + 0x348cc5, + 0x396886, + 0x23c9c5, + 0x22ae84, + 0x329743, + 0x4ee1a286, + 0x221fc5, + 0x222a85, + 0x323544, + 0x2f6283, + 0x32660c, + 0x4f208b02, + 0x4f605102, + 0x4fa02042, + 0x21a8c3, + 0x21a8c4, + 0x4fe08282, + 0x30e1c8, + 0x3b1745, + 0x2d3b84, + 0x23af86, + 0x50223502, + 0x5061b542, + 0x50a00c42, + 0x290c05, + 0x2f3886, + 0x219604, + 0x39a0c6, + 0x362dc6, + 0x211183, + 0x50ea240a, + 0x2795c5, + 0x350503, + 0x222446, + 0x3d2d09, + 0x222447, + 0x2b4d08, + 0x32f0c9, + 0x2adfc8, + 0x227d46, + 0x2105c3, + 0x512017c2, + 0x39fa08, + 0x51601f42, + 0x51a09e82, + 0x2137c3, + 0x2ec0c5, + 0x29f2c4, + 0x2fe389, + 0x2898c4, + 0x24aec8, + 0x52209e83, + 0x52696ec4, + 0x213f48, + 0x22df07, + 0x52b3d642, + 0x238442, + 0x32a385, + 0x37fc49, + 0x23c803, + 0x27e384, + 0x31d284, + 0x210943, + 0x27f28a, + 0x52e03f82, + 0x5320b182, + 0x2d5b43, + 0x390883, + 0x1627f82, + 0x374583, + 0x5361d542, + 0x53a00bc2, + 0x53f06c44, + 0x3d7846, + 0x26bbc4, + 0x277d83, + 0x281c83, + 0x54200bc3, + 0x23f7c6, + 0x208405, + 0x2d9ac7, + 0x2d9a06, + 0x2dab48, + 0x2dad46, + 0x20e944, + 0x2a0f0b, + 0x2dd603, + 0x2dd605, + 0x20f002, + 0x35fc42, + 0x54645402, + 0x54a02382, + 0x202383, + 0x54e6c9c2, + 0x26c9c3, + 0x2de083, + 0x55622902, + 0x55ae2406, + 0x258946, + 0x55e05902, + 0x5620a742, + 0x56623f82, + 0x56a15402, + 0x56e18482, + 0x57202802, + 0x214e83, + 0x385546, + 0x57619a04, + 0x213a4a, + 0x3a4986, + 0x20da84, + 0x204643, + 0x5820ce02, + 0x208482, + 0x23a0c3, + 0x5861a3c3, + 0x3bd287, + 0x3972c7, + 0x5aed3087, + 0x344407, + 0x228643, + 0x22864a, + 0x262044, + 0x31afc4, + 0x31afca, + 0x22cb45, + 0x5b21bb02, + 0x24fa03, + 0x5b600602, + 0x24e283, + 0x3b6283, + 0x5be00582, + 0x38a8c4, + 0x204484, + 0x3c2d05, + 0x3dd205, + 0x26a146, + 0x306e06, + 0x5c230a42, + 0x5c602902, + 0x310805, + 0x258652, + 0x35e586, + 0x207283, + 0x359106, + 0x2bf805, + 0x16535c2, + 0x64a0a9c2, + 0x372b43, + 0x20a9c3, + 0x292083, + 0x64e06e42, + 0x210e83, + 0x6521ad42, + 0x276e43, + 0x24b188, + 0x2624c3, + 0x2ad386, + 0x3cfc87, + 0x321486, + 0x32148b, + 0x20d9c7, + 0x31d784, + 0x65a00c02, + 0x3b15c5, + 0x65e08443, + 0x26d243, + 0x3b29c5, + 0x33f243, + 0x6673f246, + 0x3cac0a, + 0x2a7083, + 0x2366c4, + 0x2003c6, + 0x2af186, + 0x66a42543, + 0x299047, + 0x237807, + 0x2a2c85, + 0x2e4406, + 0x222003, + 0x6960f7c3, + 0x69a00a82, + 0x69e0f044, + 0x3df689, + 0x21d685, + 0x356cc4, + 0x355b48, + 0x264bc5, + 0x6a231ac5, + 0x241f49, + 0x202503, + 0x33da04, + 0x6a614282, + 0x214283, + 0x6aa57b82, + 0x257b86, + 0x1677282, + 0x6ae15302, + 0x290b08, + 0x290e03, + 0x2bf287, + 0x2b9605, + 0x2b9185, + 0x2b918b, + 0x2eec86, + 0x2b9386, + 0x27d384, + 0x2efa86, + 0x6b321708, + 0x27fd03, + 0x265f03, + 0x265f04, + 0x2ed8c4, + 0x2f6a07, + 0x315645, + 0x6b72a5c2, + 0x6ba0a882, + 0x6c21bfc5, + 0x2c1044, + 0x2e0a0b, + 0x2f7688, + 0x253604, + 0x6c62c4c2, + 0x6ca1b742, + 0x3ba2c3, + 0x2f9484, + 0x2f9745, + 0x2fa147, + 0x6cefc304, + 0x378904, + 0x6d2141c2, + 0x37ab09, + 0x2fd745, + 0x2431c5, + 0x2fe2c5, + 0x6d6141c3, + 0x237f04, + 0x237f0b, + 0x2fedc4, + 0x2ff08b, + 0x3001c5, + 0x216eca, + 0x301708, + 0x30190a, + 0x3021c3, + 0x3021ca, + 0x6de11e42, + 0x6e214b42, + 0x6e615d43, + 0x6eadbd02, + 0x3068c3, + 0x6eef6702, + 0x6f333e42, + 0x309004, + 0x2177c6, + 0x399e05, + 0x30a643, + 0x298046, + 0x399905, + 0x3573c4, + 0x6f600902, + 0x299ec4, + 0x2d5dca, + 0x2ba807, + 0x33f5c6, + 0x234207, + 0x23e343, + 0x2c29c8, + 0x3d21cb, + 0x2bc9c5, + 0x2c8b85, + 0x2c8b86, + 0x34cb84, + 0x38ab88, + 0x21aa43, + 0x26ee44, + 0x3c3747, + 0x31d3c6, + 0x380b86, + 0x2c324a, + 0x24d804, + 0x31c0ca, + 0x6fb12606, + 0x312607, + 0x255c07, + 0x2a9a04, + 0x34a189, + 0x238dc5, + 0x307a4b, + 0x2f6603, + 0x20cc83, + 0x6fe1e243, + 0x22fb84, + 0x70200682, + 0x307e06, + 0x706c60c5, + 0x359345, + 0x24fc86, + 0x2a4944, + 0x70a013c2, + 0x241e84, + 0x70e0ca42, + 0x2160c5, + 0x3b2e44, + 0x71a1c5c3, + 0x71e0aa02, + 0x20aa03, + 0x21f646, + 0x72205142, + 0x393d08, + 0x2222c4, + 0x2222c6, + 0x391106, + 0x726574c4, + 0x21a205, + 0x356d88, + 0x3577c7, + 0x2ae247, + 0x2ae24f, + 0x292f46, + 0x23d183, + 0x242144, + 0x209043, + 0x221604, + 0x24e484, + 0x72a0b382, + 0x28d203, + 0x330983, + 0x72e090c2, + 0x215803, + 0x220f03, + 0x20e2ca, + 0x273847, + 0x25284c, + 0x73252b06, + 0x252c86, + 0x255407, + 0x7362e987, + 0x25a749, + 0x308784, + 0x73a5be04, + 0x73e023c2, + 0x742045c2, + 0x2c3606, + 0x298e44, + 0x28d686, + 0x22ee08, + 0x38b944, + 0x2eafc6, + 0x28ebc5, + 0x74750788, + 0x242343, + 0x3a6b85, + 0x3aa603, + 0x2432c3, + 0x2432c4, + 0x208dc3, + 0x74a499c2, + 0x74e02d42, + 0x2f64c9, + 0x290d05, + 0x291604, + 0x29ab05, + 0x206a84, + 0x286707, + 0x35a685, + 0x7523e804, + 0x2db988, + 0x2dcdc6, + 0x2e2d44, + 0x2e6e08, + 0x2e7447, + 0x75607842, + 0x2ef184, + 0x314cc4, + 0x2c9247, + 0x75a07844, + 0x24a682, + 0x75e02f82, + 0x210883, + 0x2e5ac4, + 0x299943, + 0x2b2cc5, + 0x7622ae42, + 0x309345, + 0x23c7c2, + 0x30f885, + 0x23c7c5, + 0x76607242, + 0x327704, + 0x76a071c2, + 0x33d486, + 0x2c8686, + 0x37fd88, + 0x2c9c08, + 0x380e04, + 0x3cdb05, + 0x310389, + 0x2f0684, + 0x3cabc4, + 0x288b03, + 0x26c703, + 0x76f02905, + 0x3829c5, + 0x283644, + 0x359b4d, + 0x294ec2, + 0x376403, + 0x77206382, + 0x77603242, + 0x3937c5, + 0x24b447, + 0x224244, + 0x32f2c9, + 0x2d5f09, + 0x2770c3, + 0x2770c8, + 0x312b09, + 0x21e7c7, + 0x77a08805, + 0x396406, + 0x3a06c6, + 0x3a8645, + 0x377285, + 0x77e01bc2, + 0x27a585, + 0x2bd4c8, + 0x2cb646, + 0x783b4347, + 0x2cf3c4, + 0x2da987, + 0x30b306, + 0x78601082, + 0x396586, + 0x30ef0a, + 0x30f785, + 0x78af00c2, + 0x78e11102, + 0x365486, + 0x211108, + 0x7928df87, + 0x79601402, + 0x214b83, + 0x3c0706, + 0x2caac4, + 0x346ac6, + 0x271ac6, + 0x26930a, + 0x2047c5, + 0x286f06, + 0x384643, + 0x384644, + 0x79a35002, + 0x2869c3, + 0x79e1a902, + 0x2ea903, + 0x7a218ac4, + 0x211244, + 0x7a61124a, + 0x21bd03, + 0x237ac7, + 0x313146, + 0x33c284, + 0x20d942, + 0x2aad42, + 0x7aa007c2, + 0x226e83, + 0x2559c7, 0x2007c7, - 0x287dc4, - 0x3d0847, - 0x2f0706, - 0x20fb07, - 0x227544, - 0x292445, - 0x2187c5, - 0x78214682, - 0x3b2f46, - 0x215943, - 0x21e0c2, - 0x21e0c6, - 0x78621542, - 0x78a19f82, - 0x298e05, - 0x78e47c82, - 0x79201942, - 0x324c85, - 0x2d3985, - 0x2a9385, - 0x79a1d043, - 0x24adc5, - 0x2e82c7, - 0x2f3505, - 0x202385, - 0x32b944, - 0x229a46, - 0x3dd844, - 0x79e008c2, - 0x7ab82d05, - 0x3c9447, - 0x3afe08, - 0x24d686, - 0x38bb4d, - 0x24d689, - 0x24d692, - 0x34cf05, - 0x37aa03, - 0x7ae06902, - 0x319b44, - 0x2145c3, - 0x38d005, - 0x30b405, - 0x7b20ff42, - 0x259243, - 0x7b62b902, - 0x7beca302, - 0x7c200082, - 0x2e08c5, - 0x2088c3, - 0x7c60fa02, - 0x7ca14302, - 0x3a4486, - 0x27ac8a, - 0x208c83, - 0x256203, - 0x2f6ac3, - 0x7de05402, - 0x8c218d82, - 0x8ca05782, - 0x217042, - 0x3cd2c9, - 0x2c80c4, - 0x2d6648, - 0x8cefbb02, - 0x8d60ff82, - 0x2c4e85, - 0x233b08, - 0x23c708, - 0x315b0c, - 0x237843, - 0x8da08842, - 0x8de00f02, - 0x3b9686, - 0x30df85, - 0x2dae43, - 0x252f86, - 0x30e0c6, - 0x27a383, - 0x310c83, - 0x311346, - 0x312bc4, - 0x263546, - 0x3b610a, - 0x23fbc4, - 0x313284, - 0x314aca, - 0x8e212f42, - 0x24cf45, - 0x31634a, - 0x316285, - 0x317c04, - 0x317d06, - 0x317e84, - 0x216486, - 0x8e615482, - 0x215486, - 0x251a45, - 0x3b2dc7, - 0x3b5f86, - 0x254f84, - 0x2db0c7, - 0x20a4c5, - 0x20a4c7, - 0x3b7147, - 0x3b714e, - 0x389606, - 0x22a785, - 0x205b07, - 0x207203, - 0x207207, - 0x21e905, - 0x225944, - 0x22a582, - 0x23db47, - 0x30b144, - 0x241b04, - 0x285f4b, - 0x21c283, - 0x2bc607, - 0x21c284, - 0x2bc907, - 0x229683, - 0x350f8d, - 0x3a0c48, - 0x8ea46384, - 0x246385, - 0x3194c5, - 0x319903, - 0x8ee25242, - 0x31c243, - 0x31d283, - 0x3b30c4, - 0x27cf45, - 0x2159c7, - 0x252146, - 0x38cdc3, - 0x22b34b, - 0x27350b, - 0x2ac28b, - 0x3cad8b, - 0x2e8fca, - 0x36f44b, - 0x39334b, - 0x3d950c, - 0x3dcb4b, - 0x31ddd1, - 0x31e20a, - 0x31e70b, - 0x31e9cc, - 0x31eccb, - 0x31ff4a, - 0x3206ca, - 0x321ece, - 0x32344b, - 0x32370a, - 0x324dd1, - 0x32520a, - 0x32570b, - 0x325c4e, - 0x326b4c, - 0x32738b, - 0x32764e, - 0x3279cc, - 0x32b40a, - 0x32c64c, - 0x8f32c94a, - 0x32d548, - 0x32e109, - 0x33204a, - 0x3322ca, - 0x33254b, - 0x334cce, - 0x335b91, - 0x341509, - 0x34174a, - 0x34244b, - 0x34634d, - 0x3471ca, - 0x348716, - 0x349a8b, - 0x34a80a, - 0x34ad8a, - 0x34c10b, - 0x34c989, - 0x351909, - 0x351e8d, - 0x35250b, - 0x35340b, - 0x353dcb, - 0x3543c9, - 0x354a0e, - 0x35520a, - 0x35608a, - 0x35698a, - 0x35724b, - 0x357a8b, - 0x35890d, - 0x35a04d, - 0x35a950, - 0x35ae0b, - 0x35b90c, - 0x35cecb, - 0x35ec0b, - 0x3602ce, - 0x3609cb, - 0x3609cd, - 0x36550b, - 0x365f8f, - 0x36634b, - 0x366b8a, - 0x3678c9, - 0x367f89, - 0x8f7689cb, - 0x368c8e, - 0x36900e, - 0x36cecb, - 0x36e00f, - 0x37024b, - 0x37050b, - 0x3707cb, - 0x370e8a, - 0x377889, - 0x37a00f, - 0x37e9cc, - 0x37ee0c, - 0x37f8ce, - 0x37fe4f, - 0x38020e, - 0x381310, - 0x38170f, - 0x3822ce, - 0x382e8c, - 0x383191, - 0x3835d2, - 0x384ad1, - 0x3852ce, - 0x38570b, - 0x38570e, - 0x385a8f, - 0x385e4e, - 0x3861d3, - 0x386691, - 0x386acc, - 0x386dce, - 0x38724c, - 0x387793, - 0x388650, - 0x38a34c, - 0x38a64c, - 0x38ab0b, - 0x38b0ce, - 0x38b5cb, - 0x38be8b, - 0x38d30c, - 0x39278a, - 0x392b4c, - 0x392e4c, - 0x393149, - 0x39494b, - 0x394c08, - 0x3953c9, - 0x3953cf, - 0x396c8b, - 0x8fb9800a, - 0x399fcc, - 0x39b18b, - 0x39b449, - 0x39bbc8, - 0x39c18b, - 0x39c70b, - 0x39d28a, - 0x39d50b, - 0x39da0c, - 0x39e3c9, - 0x39e608, - 0x3a0f8b, - 0x3a3ccb, - 0x3a694e, - 0x3a7e4b, - 0x3aabcb, - 0x3b6ccb, - 0x3b6f89, - 0x3b74cd, - 0x3c9e8a, - 0x3cdd57, - 0x3cf418, - 0x3d41c9, - 0x3d530b, - 0x3d5814, - 0x3d5d0b, - 0x3d628a, - 0x3d694a, - 0x3d6bcb, - 0x3d7410, - 0x3d7811, - 0x3d7eca, - 0x3d8b0d, - 0x3d920d, - 0x3ddd8b, - 0x3b3043, - 0x8ff83d43, - 0x32af06, - 0x22ef05, - 0x307347, - 0x332e46, - 0x1602d42, - 0x2ab3c9, - 0x32d1c4, - 0x2e4d08, - 0x21dd43, - 0x319a87, - 0x22de82, - 0x2b05c3, - 0x902057c2, - 0x2cc446, - 0x2cdb04, - 0x347d04, - 0x346243, - 0x90ac91c2, - 0x90e2a444, - 0x273e47, - 0x9122a1c2, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x211543, - 0x20a803, - 0x216603, - 0x111148, - 0x20ca43, + 0x285d84, + 0x3da107, + 0x2fa246, + 0x210d47, + 0x220e44, + 0x2ae145, + 0x205345, + 0x7ae1e502, + 0x3d7286, + 0x220383, + 0x2266c2, + 0x2266c6, + 0x7b21f3c2, + 0x7b633442, + 0x29d005, + 0x7ba02c02, + 0x7be02982, + 0x324605, + 0x2d7505, + 0x2ac745, + 0x7c65b003, + 0x279a45, + 0x2eed47, + 0x36cc85, + 0x204985, + 0x261f44, + 0x264a46, + 0x38e104, + 0x7ca008c2, + 0x7d793085, + 0x3cb087, + 0x3c0bc8, + 0x253c46, + 0x253c4d, + 0x262d49, + 0x262d52, + 0x37a385, + 0x37ae03, + 0x7da09d42, + 0x3027c4, + 0x226603, + 0x3cb985, + 0x310f85, + 0x7de0c782, + 0x25a6c3, + 0x7e226dc2, + 0x7ea1d602, + 0x7ee00082, + 0x2e9bc5, + 0x207643, + 0x7f205b02, + 0x7f60c2c2, + 0x38a886, + 0x2d020a, + 0x215003, + 0x2579c3, + 0x2ff8c3, + 0x80e01b82, + 0x8f20c1c2, + 0x8fa0a5c2, + 0x203642, + 0x3ce689, + 0x2ce144, + 0x2dfac8, + 0x8ff04382, + 0x90606482, + 0x3bd905, + 0x233c88, + 0x231148, + 0x2f738c, + 0x2398c3, + 0x90a075c2, + 0x90e00f02, + 0x24ac46, + 0x313fc5, + 0x295b43, + 0x254686, + 0x314106, + 0x296b03, + 0x314c03, + 0x315046, + 0x316884, + 0x29cc86, + 0x23cd44, + 0x316f44, + 0x31784a, + 0x912b7402, + 0x24e705, + 0x3193ca, + 0x319305, + 0x31a7c4, + 0x31a8c6, + 0x31aa44, + 0x214546, + 0x91602b42, + 0x24c5c6, + 0x33bf85, + 0x286d87, + 0x33a106, + 0x255604, + 0x2e3407, + 0x234f85, + 0x23b687, + 0x3bc247, + 0x3bc24e, + 0x278646, + 0x222705, + 0x207787, + 0x20a783, + 0x3d3a47, + 0x20ab85, + 0x2123c4, + 0x22a8c2, + 0x325ec7, + 0x310cc4, + 0x23dec4, + 0x284a4b, + 0x21cb83, + 0x2c4907, + 0x21cb84, + 0x2c4c07, + 0x3a6603, + 0x34e40d, + 0x3a2f88, + 0x91a292c4, + 0x23e705, + 0x31b805, + 0x31bc43, + 0x91e221c2, + 0x31d1c3, + 0x31e083, + 0x3d7404, + 0x27bf85, + 0x220407, + 0x3846c6, + 0x38d943, + 0x22680b, + 0x249b8b, + 0x2acfcb, + 0x2c174b, + 0x3ccd4a, + 0x31734b, + 0x36ea8b, + 0x394e0c, + 0x3ada0b, + 0x3bf811, + 0x3dcf4a, + 0x31f58b, + 0x31f84c, + 0x31fb4b, + 0x3200ca, + 0x3209ca, + 0x3221ce, + 0x32294b, + 0x322c0a, + 0x324751, + 0x324b8a, + 0x32508b, + 0x3255ce, + 0x326c8c, + 0x32784b, + 0x327b0e, + 0x327e8c, + 0x328bca, + 0x329d4c, + 0x9232a04a, + 0x32a808, + 0x32b3c9, + 0x32ce8a, + 0x32d10a, + 0x32d38b, + 0x33010e, + 0x3316d1, + 0x33e209, + 0x33e44a, + 0x33ee8b, + 0x33fc0d, + 0x340a8a, + 0x341616, + 0x34298b, + 0x34668a, + 0x347d0a, + 0x3490cb, + 0x34aa49, + 0x34ed89, + 0x34f30d, + 0x34fe0b, + 0x351c8b, + 0x352509, + 0x352b4e, + 0x35328a, + 0x353dca, + 0x35438a, + 0x354a0b, + 0x35524b, + 0x3585cd, + 0x35a18d, + 0x35b050, + 0x35b50b, + 0x35ce4c, + 0x35d98b, + 0x35f44b, + 0x360c4e, + 0x36128b, + 0x36128d, + 0x3663cb, + 0x366e4f, + 0x36720b, + 0x36860a, + 0x368e49, + 0x369509, + 0x9276988b, + 0x369b4e, + 0x369ece, + 0x36be8b, + 0x36d64f, + 0x370acb, + 0x370d8b, + 0x37104b, + 0x37164a, + 0x3764c9, + 0x37964f, + 0x37e24c, + 0x37f30c, + 0x38058e, + 0x3810cf, + 0x38148e, + 0x381e50, + 0x38224f, + 0x382b4e, + 0x38320c, + 0x383511, + 0x383952, + 0x3856d1, + 0x385dce, + 0x38620b, + 0x38620e, + 0x38658f, + 0x38694e, + 0x386cd3, + 0x387191, + 0x3875cc, + 0x3878ce, + 0x387d4c, + 0x388293, + 0x388a90, + 0x389b8c, + 0x389e8c, + 0x38a34b, + 0x38ae4e, + 0x38b34b, + 0x38cb4b, + 0x38ddcc, + 0x39424a, + 0x39460c, + 0x39490c, + 0x394c09, + 0x396a0b, + 0x396cc8, + 0x397509, + 0x39750f, + 0x3991cb, + 0x92b9a54a, + 0x39bd0c, + 0x39cccb, + 0x39cf89, + 0x39d348, + 0x39da4b, + 0x39df4b, + 0x39eb8a, + 0x39ee0b, + 0x39f78c, + 0x3a0149, + 0x3a0388, + 0x3a3d0b, + 0x3a6f4b, + 0x3a91ce, + 0x3aaf4b, + 0x3ad38b, + 0x3bbdcb, + 0x3bc089, + 0x3bc5cd, + 0x3cbe4a, + 0x3cf5d7, + 0x3d18d8, + 0x3d5909, + 0x3d6b0b, + 0x3d79d4, + 0x3d7ecb, + 0x3d844a, + 0x3d894a, + 0x3d8bcb, + 0x3da790, + 0x3dab91, + 0x3db24a, + 0x3dc54d, + 0x3dcc4d, + 0x3e06cb, + 0x3d7383, + 0x92f9b403, + 0x289b06, + 0x246085, + 0x30ccc7, + 0x2ef746, + 0x165c942, + 0x270b89, + 0x297e44, + 0x2ed408, + 0x21e183, + 0x302707, + 0x205602, + 0x2b5503, + 0x93201442, + 0x2d69c6, + 0x2d8084, + 0x38f1c4, + 0x268643, + 0x93ad3982, + 0x93e2a784, + 0x34a0c7, + 0x9422a502, + 0x214a83, + 0x232dc3, + 0x308003, + 0x23c803, + 0x21a3c3, + 0x242543, + 0x105dc8, + 0x203dc3, 0x2000c2, - 0x9fe08, - 0x20c302, - 0x228b03, - 0x211543, - 0x20a803, - 0xca43, - 0x216603, - 0x20c603, - 0x33b8d6, - 0x363e93, - 0x3d06c9, - 0x322c48, - 0x3b85c9, - 0x3164c6, - 0x3527d0, - 0x20c013, - 0x2ebc08, - 0x27a947, - 0x286b07, - 0x2a4a4a, - 0x3291c9, - 0x28f509, - 0x24224b, - 0x2e73c6, - 0x28830a, - 0x222a86, - 0x32cdc3, - 0x256545, - 0x3a8908, - 0x233fcd, - 0x21fd0c, - 0x2eaac7, - 0x3dcdcd, - 0x225744, - 0x22fd8a, - 0x23084a, - 0x230d0a, - 0x20c307, - 0x23a907, - 0x23da84, - 0x287806, - 0x251c04, - 0x2d58c8, - 0x32ad09, - 0x2cf506, - 0x2cf508, - 0x240dcd, - 0x2cbc09, - 0x3910c8, - 0x240907, - 0x23750a, - 0x24e606, - 0x25b7c7, - 0x2fb704, - 0x20b6c7, - 0x228b0a, - 0x239d4e, - 0x277f05, - 0x3d7c0b, - 0x22b709, - 0x24d8c9, - 0x2c6607, - 0x3c138a, - 0x2c2cc7, - 0x2f9309, - 0x27b408, - 0x2e640b, - 0x2e2a45, - 0x22ad8a, - 0x22b0c9, - 0x33e68a, - 0x20460b, - 0x20b5cb, - 0x241fd5, - 0x2c1f85, - 0x240985, - 0x2f67ca, - 0x3dbb0a, - 0x31b687, - 0x233c43, - 0x2ba388, - 0x2d80ca, - 0x225346, - 0x2592c9, - 0x28a748, - 0x2dedc4, - 0x387549, - 0x2c3748, - 0x2c2407, - 0x382d06, - 0x3c9447, - 0x2b4607, - 0x23ca85, - 0x2e450c, - 0x246385, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x20a803, - 0xca43, - 0x216603, - 0x20c302, - 0x22c0c3, - 0x20a803, - 0x20ca43, - 0x216603, - 0x22c0c3, - 0x20a803, - 0xca43, - 0x239503, - 0x216603, - 0x1ca243, - 0x9fe08, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x211543, - 0x20a803, - 0xca43, - 0x216603, - 0x9fe08, - 0x20c302, - 0x22c0c3, - 0x22c0c7, - 0x20a803, - 0x216603, - 0x20c302, - 0x201d02, - 0x2ebe82, - 0x202cc2, - 0x202f82, - 0x2e5382, - 0x91746, - 0x4e9c9, - 0x481b443, - 0x88147, - 0x5b03, - 0x119045, + 0x9a048, + 0x201242, + 0x308003, + 0x23c803, + 0x21a3c3, + 0x3dc3, + 0x242543, + 0x20e2c3, + 0x337396, + 0x364d53, + 0x3d9f89, + 0x2135c8, + 0x3b1449, + 0x319546, + 0x351190, + 0x20dcd3, + 0x31d488, + 0x277e87, + 0x279e87, + 0x2a86ca, + 0x343189, + 0x267d49, + 0x2d368b, + 0x303c06, + 0x30334a, + 0x2205c6, + 0x32a4c3, + 0x2e2905, + 0x3ba348, + 0x27decd, + 0x2f330c, + 0x2ec347, + 0x30bfcd, + 0x2136c4, + 0x22fe4a, + 0x23134a, + 0x23180a, + 0x20dfc7, + 0x23cb87, + 0x240104, + 0x273506, + 0x348a44, + 0x304c08, + 0x289909, + 0x2e6606, + 0x2e6608, + 0x24360d, + 0x2d6149, + 0x392488, + 0x243147, + 0x3b27ca, + 0x250086, + 0x2fd244, + 0x212107, + 0x30800a, + 0x3ab68e, + 0x277185, + 0x3daf8b, + 0x226bc9, + 0x22e0c9, + 0x2b3147, + 0x3d090a, + 0x2c9187, + 0x2ff649, + 0x33b048, + 0x2a5e8b, + 0x2ec0c5, + 0x22c50a, + 0x223d49, + 0x295aca, + 0x20f30b, + 0x21200b, + 0x2d3415, + 0x2c8205, + 0x2431c5, + 0x237f0a, + 0x22b98a, + 0x2f5d87, + 0x233dc3, + 0x2c3588, + 0x2e0eca, + 0x2222c6, + 0x259c09, + 0x350788, + 0x2e2d44, + 0x388049, + 0x2c9c08, + 0x2ca947, + 0x393086, + 0x3cb087, + 0x2be807, + 0x23f5c5, + 0x2d314c, + 0x23e705, + 0x214a83, + 0x232dc3, + 0x308003, + 0x21a3c3, + 0x3dc3, + 0x242543, + 0x201242, + 0x214a83, + 0x21a3c3, + 0x203dc3, + 0x242543, + 0x214a83, + 0x21a3c3, + 0x3dc3, + 0x2624c3, + 0x242543, + 0x1cc203, + 0x9a048, + 0x214a83, + 0x232dc3, + 0x308003, + 0x23c803, + 0x21a3c3, + 0x3dc3, + 0x242543, + 0x9a048, + 0x201242, + 0x214a83, + 0x22ca07, + 0x86504, + 0x21a3c3, + 0x97a04, + 0x242543, + 0x201242, + 0x2052c2, + 0x3192c2, + 0x207882, + 0x201582, + 0x2eda82, + 0x908c6, + 0x50849, + 0xf3fc7, + 0x481c5c3, + 0x86107, + 0x148406, + 0x7783, + 0x11af85, 0xc1, - 0x522c0c3, - 0x232c43, - 0x212483, - 0x228b03, - 0x214543, - 0x211543, - 0x2d9fc6, - 0x20a803, - 0x216603, - 0x20f803, - 0x9fe08, - 0x3443c4, - 0x374787, - 0x346283, - 0x2b3904, - 0x218c83, - 0x286243, - 0x228b03, - 0x176c87, + 0x5214a83, + 0x232dc3, + 0x228503, + 0x308003, + 0x21bc83, + 0x23c803, + 0x2e2806, + 0x21a3c3, + 0x242543, + 0x233d43, + 0x9a048, + 0x345b44, + 0x296c87, + 0x268683, + 0x2bad84, + 0x2187c3, + 0x284d43, + 0x308003, + 0x17e707, 0x9c4, - 0x11c3, - 0x2b05, - 0x2000c2, - 0x48343, - 0x660c302, - 0x688a549, - 0x8abcd, - 0x8af0d, - 0x2ebe82, - 0x24e44, - 0x2b49, + 0x4e83, + 0x68b05, + 0x66000c2, + 0x2703, + 0x6a01242, + 0x6c8c109, + 0x8c98d, + 0x8cccd, + 0x3192c2, + 0x21dc4, + 0x68b49, 0x2003c2, - 0x6e24d48, - 0xf61c4, - 0x9fe08, - 0x1417c42, + 0x7221cc8, + 0xfe7c4, + 0x31c843, + 0x9a048, + 0x1414882, 0x14005c2, - 0x1417c42, - 0x1513486, - 0x22df03, - 0x26fb43, - 0x762c0c3, - 0x22fd84, - 0x7a32c43, - 0x8628b03, - 0x203dc2, - 0x224e44, - 0x20a803, - 0x2e59c3, - 0x201e02, - 0x216603, - 0x2185c2, - 0x301e43, - 0x204e82, - 0x203303, - 0x28a803, - 0x205842, - 0x9fe08, - 0x22df03, - 0x3c38c8, - 0x7ee59c3, - 0x201e02, - 0x301e43, - 0x204e82, - 0x8203303, - 0x28a803, - 0x205842, - 0x253c47, - 0x232c49, - 0x301e43, - 0x204e82, - 0x203303, - 0x28a803, - 0x205842, - 0x22c0c3, - 0x248343, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x224e44, - 0x214543, - 0x211543, - 0x217b84, - 0x20a803, - 0x216603, - 0x20b142, - 0x216103, - 0x9fe08, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x211543, - 0x20a803, - 0x216603, - 0x248343, - 0x20c302, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x224e44, - 0x20a803, - 0x216603, - 0x204185, - 0x20ff42, + 0x1414882, + 0x1517146, + 0x22f043, + 0x26f6c3, + 0x7a14a83, + 0x22fe44, + 0x7e32dc3, + 0x8b08003, + 0x206182, + 0x221dc4, + 0x21a3c3, + 0x3b1e83, + 0x204042, + 0x242543, + 0x202642, + 0x308f43, + 0x205142, + 0x2263c3, + 0x223a43, + 0x201342, + 0x9a048, + 0x22f043, + 0x3df888, + 0x83b1e83, + 0x204042, + 0x308f43, + 0x205142, + 0x86263c3, + 0x223a43, + 0x201342, + 0x252b07, + 0x232dc9, + 0x308f43, + 0x205142, + 0x2263c3, + 0x223a43, + 0x201342, + 0x214a83, + 0x16c2, + 0x32443, + 0x3c42, + 0xaac82, + 0x5cd82, + 0x17c2, + 0x1b82, + 0x43342, + 0x202703, + 0x214a83, + 0x232dc3, + 0x308003, + 0x221dc4, + 0x21bc83, + 0x23c803, + 0x219a04, + 0x21a3c3, + 0x242543, + 0x20eb02, + 0x2141c3, + 0x9a048, + 0x214a83, + 0x232dc3, + 0x308003, + 0x23c803, + 0x21a3c3, + 0x242543, + 0x202703, + 0x201242, + 0x214a83, + 0x232dc3, + 0x308003, + 0x221dc4, + 0x21a3c3, + 0x242543, + 0x208805, + 0x20c782, 0x2000c2, - 0x9fe08, - 0x14470c8, - 0xf704a, - 0x228b03, - 0x203281, + 0x9a048, + 0x144ca88, + 0x12848a, + 0x308003, + 0x225cc1, 0x2009c1, 0x200a01, - 0x201301, - 0x201281, - 0x207101, - 0x2027c1, - 0x2223c1, - 0x203bc1, + 0x204ac1, + 0x204781, + 0x20a541, + 0x201941, + 0x225dc1, + 0x23ff81, 0x200001, 0x2000c1, 0x200201, - 0x12eb85, - 0x9fe08, + 0x139b05, + 0x9a048, 0x200101, - 0x2015c1, + 0x201301, 0x200501, - 0x2014c1, + 0x205dc1, 0x200041, 0x200801, 0x200181, @@ -2337,7112 +2348,7193 @@ var nodes = [...]uint32{ 0x200581, 0x2003c1, 0x200a81, - 0x209101, + 0x215481, 0x200401, 0x200741, 0x2007c1, 0x200081, 0x200f01, - 0x205841, - 0x201241, - 0x2018c1, - 0x204981, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x20a803, - 0x216603, - 0x20c302, - 0x22c0c3, - 0x232c43, + 0x201341, + 0x204f01, + 0x201b41, + 0x201441, + 0x214a83, + 0x232dc3, + 0x308003, + 0x21a3c3, + 0x242543, + 0x201242, + 0x214a83, + 0x232dc3, 0x2003c2, - 0x216603, - 0x1ae03, - 0x176c87, - 0x11647, - 0x39346, - 0x3484a, - 0x89988, - 0x53388, - 0x53f47, - 0xbdc06, - 0xe1145, - 0x175305, - 0x125b03, - 0x13686, - 0x3e006, - 0x242244, - 0x2f6d07, - 0x9fe08, - 0x2db1c4, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x20a803, - 0x216603, - 0xc302, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x20a803, - 0x216603, - 0x32cb48, - 0x345344, - 0x232b84, - 0x26bb44, - 0x3b9587, - 0x2d6b87, - 0x22c0c3, - 0x23560b, - 0x37400a, - 0x2ff007, - 0x308a08, - 0x2f7b48, - 0x232c43, - 0x2e6687, - 0x212483, - 0x204f48, - 0x209c89, - 0x224e44, - 0x214543, - 0x238cc8, - 0x211543, - 0x2d378a, - 0x2d9fc6, - 0x3a5d47, - 0x20a803, - 0x373846, - 0x26f9c8, - 0x216603, - 0x2433c6, - 0x2edf0d, - 0x2f0348, - 0x2f8a8b, - 0x20b186, - 0x3baac7, - 0x212605, - 0x3c554a, - 0x222085, - 0x2410ca, - 0x20ff42, - 0x205b03, - 0x241b04, + 0x242543, + 0x1bf83, + 0x17e707, + 0xd1407, + 0x28886, + 0x34b8a, + 0x8b848, + 0x54e08, + 0x558c7, + 0x174586, + 0xea585, + 0x97805, + 0x125483, + 0x11ec6, + 0x365c6, + 0x2d3684, + 0x328147, + 0x9a048, + 0x2e3504, + 0x214a83, + 0x232dc3, + 0x308003, + 0x21a3c3, + 0x242543, + 0x1242, + 0x214a83, + 0x232dc3, + 0x308003, + 0x21a3c3, + 0x242543, + 0x32a248, + 0x204244, + 0x232d04, + 0x229904, + 0x24ab47, + 0x2e0007, + 0x214a83, + 0x235b4b, + 0x29650a, + 0x33c147, + 0x23bc48, + 0x33b888, + 0x232dc3, + 0x287847, + 0x228503, + 0x206f88, + 0x2130c9, + 0x221dc4, + 0x21bc83, + 0x23b248, + 0x23c803, + 0x2dd74a, + 0x2e2806, + 0x3a4987, + 0x21a3c3, + 0x267906, + 0x26f548, + 0x242543, + 0x24d446, + 0x2f78cd, + 0x2f9e08, + 0x2fedcb, + 0x20eb46, + 0x24b347, + 0x2225c5, + 0x21674a, + 0x308245, + 0x3828ca, + 0x20c782, + 0x207783, + 0x23dec4, 0x200006, - 0x3ae643, - 0x29fd03, - 0x258783, - 0x20f643, - 0x373c83, - 0x203582, - 0x3abe85, - 0x2aad89, - 0x23d103, - 0x225843, - 0x215203, + 0x3b05c3, + 0x299f43, + 0x27ee03, + 0x204243, + 0x296183, + 0x2041c2, + 0x355dc5, + 0x2ad8c9, + 0x23fc43, + 0x220dc3, + 0x21fdc3, 0x200201, - 0x2cfb07, - 0x2e0605, - 0x3a8843, - 0x3c7543, - 0x26bb44, - 0x2fef83, - 0x21b908, - 0x367b03, - 0x30f30d, - 0x3896c8, - 0x3c3a86, - 0x2fdec3, - 0x360cc3, - 0x38d5c3, - 0xc62c0c3, - 0x232488, - 0x235604, - 0x23e483, + 0x2f0447, + 0x2e9905, + 0x3b5c03, + 0x3d6d83, + 0x229904, + 0x343a43, + 0x20ff88, + 0x35d143, + 0x30d98d, + 0x278708, + 0x3dfa46, + 0x286a03, + 0x361583, + 0x38e083, + 0xce14a83, + 0x232608, + 0x235b44, + 0x240983, 0x200106, - 0x241648, - 0x27c083, - 0x3c5583, - 0x22c243, - 0x232c43, - 0x2234c3, - 0x2420c3, - 0x284ac3, - 0x3313c3, - 0x28c603, - 0x20d643, - 0x38c105, - 0x24e984, - 0x24f307, - 0x2b12c2, - 0x252d83, - 0x256cc6, - 0x258283, - 0x258e03, - 0x277e03, - 0x2be4c3, - 0x3440c3, - 0x297e47, - 0xca28b03, - 0x2530c3, - 0x3d9e83, - 0x204f43, - 0x214383, - 0x2157c3, - 0x3c3345, - 0x372f03, + 0x243d88, + 0x27b0c3, + 0x216783, + 0x22d1c3, + 0x232dc3, + 0x21afc3, + 0x2532c3, + 0x283603, + 0x286983, + 0x2cbf83, + 0x2196c3, + 0x38b5c5, + 0x250804, + 0x251987, + 0x22dec2, + 0x254483, + 0x257d06, + 0x2592c3, + 0x25a283, + 0x277083, + 0x374e43, + 0x345843, + 0x29c047, + 0xd308003, + 0x2425c3, + 0x286a43, + 0x206c03, + 0x21bac3, + 0x24c903, + 0x20ef85, + 0x373c83, 0x200e09, - 0x201503, - 0x30b703, - 0xce35c03, - 0x2c9343, - 0x219a08, - 0x2aacc6, - 0x2be286, - 0x2b1306, - 0x388d07, - 0x228503, - 0x238cc3, - 0x211543, - 0x289a86, - 0x21fdc2, - 0x28f543, - 0x33a385, - 0x20a803, - 0x316d07, - 0x160ca43, - 0x26f9c3, - 0x204343, - 0x230743, - 0x21d283, - 0x216603, - 0x20dc46, - 0x3b9d86, - 0x37a8c3, - 0x2ef183, - 0x216103, - 0x2275c3, - 0x310d03, - 0x2fd203, - 0x302203, - 0x3973c5, - 0x236bc3, - 0x236bc6, - 0x211f08, - 0x212983, - 0x212989, - 0x33f908, - 0x216f88, - 0x221105, - 0x22ceca, - 0x22e04a, - 0x237acb, - 0x23a5c8, - 0x2ed803, - 0x38cf03, - 0x2f9503, - 0x30e208, - 0x3606c3, - 0x2520c4, - 0x207442, - 0x25c283, + 0x20bb83, + 0x311283, + 0xd63c883, + 0x2d3b03, + 0x219208, + 0x2ad806, + 0x374c06, + 0x2b7106, + 0x389147, + 0x227d43, + 0x2137c3, + 0x23c803, + 0x28b946, + 0x20f002, + 0x267d83, + 0x353145, + 0x21a3c3, + 0x319e87, + 0x1603dc3, + 0x202903, + 0x2089c3, + 0x21fec3, + 0x26d243, + 0x242543, + 0x209006, + 0x3b5f86, + 0x37a243, + 0x2f8a83, + 0x2141c3, + 0x220ec3, + 0x314c83, + 0x305fc3, + 0x309303, + 0x399905, + 0x22b983, + 0x39f446, + 0x2d1cc8, + 0x20cc83, + 0x20cc89, + 0x298948, + 0x223488, + 0x229a85, + 0x22f18a, + 0x23818a, + 0x239b4b, + 0x23b808, + 0x398943, + 0x38da83, + 0x30a583, + 0x326f48, + 0x376dc3, + 0x384644, + 0x235002, + 0x25ca83, 0x2007c3, - 0x228803, - 0x250d43, - 0x20f803, - 0x20ff42, - 0x229543, - 0x237843, - 0x313603, - 0x315504, - 0x241b04, - 0x3ced43, - 0x9fe08, + 0x356c43, + 0x263343, + 0x233d43, + 0x20c782, + 0x229e43, + 0x2398c3, + 0x3172c3, + 0x318284, + 0x23dec4, + 0x20fe43, + 0x9a048, 0x2000c2, 0x200ac2, - 0x203582, - 0x202542, + 0x2041c2, + 0x204b42, 0x200202, - 0x201ec2, - 0x25a902, - 0x201bc2, + 0x204342, + 0x240702, + 0x203c42, 0x200382, 0x200c42, - 0x252742, - 0x205a02, - 0x26bf42, + 0x33d642, + 0x202382, + 0x26c9c2, 0x200a82, - 0x2e5382, - 0x2161c2, - 0x201c82, - 0x216102, - 0x228702, - 0x204d42, + 0x2eda82, + 0x214282, + 0x205742, + 0x2141c2, + 0x2c1902, + 0x2069c2, 0x200682, - 0x216c82, - 0x202442, - 0x209482, - 0x202e42, - 0x2411c2, - 0x201942, + 0x206f02, + 0x2013c2, + 0x2090c2, + 0x2045c2, + 0x26c702, + 0x202982, 0xc2, 0xac2, - 0x3582, - 0x2542, + 0x41c2, + 0x4b42, 0x202, - 0x1ec2, - 0x5a902, - 0x1bc2, + 0x4342, + 0x40702, + 0x3c42, 0x382, 0xc42, - 0x52742, - 0x5a02, - 0x6bf42, + 0x13d642, + 0x2382, + 0x6c9c2, 0xa82, - 0xe5382, - 0x161c2, - 0x1c82, - 0x16102, - 0x28702, - 0x4d42, + 0xeda82, + 0x14282, + 0x5742, + 0x141c2, + 0xc1902, + 0x69c2, 0x682, - 0x16c82, - 0x2442, - 0x9482, - 0x2e42, - 0x411c2, - 0x1942, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x20a803, - 0x216603, - 0x5b02, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x20a803, - 0x216603, - 0xc302, - 0x20c302, - 0x216603, - 0xe62c0c3, - 0x228b03, - 0x211543, - 0x6d9c3, - 0x22d7c2, - 0x9fe08, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x20a803, - 0x6d9c3, - 0x216603, - 0x57c2, + 0x6f02, + 0x13c2, + 0x90c2, + 0x45c2, + 0x6c702, + 0x2982, + 0x214a83, + 0x232dc3, + 0x308003, + 0x21a3c3, + 0x242543, + 0x7782, + 0x214a83, + 0x232dc3, + 0x308003, + 0x21a3c3, + 0x242543, + 0x1242, + 0x201242, + 0x242543, + 0xee14a83, + 0x308003, + 0x23c803, + 0x1b4103, + 0x22aec2, + 0x9a048, + 0x214a83, + 0x232dc3, + 0x308003, + 0x21a3c3, + 0x3dc3, + 0x1b4103, + 0x242543, + 0x1442, 0x2001c2, - 0x154da85, - 0x12eb85, - 0x208602, - 0x9fe08, - 0xc302, - 0x234482, - 0x204b02, + 0x15c45c5, + 0x139b05, + 0x20b3c2, + 0x9a048, + 0x1242, + 0x2347c2, + 0x206782, + 0x204642, 0x21bb02, - 0x211482, - 0x239242, - 0x175305, - 0x2016c2, - 0x201e02, - 0x218d42, - 0x201dc2, - 0x2161c2, - 0x23d182, - 0x201782, - 0x296542, - 0xf73f344, + 0x230a42, + 0x97805, + 0x202f42, + 0x204042, + 0x206e42, + 0x205e42, + 0x214282, + 0x23fcc2, + 0x202f82, + 0x292882, + 0xfe98384, 0x142, - 0x176c87, - 0x1266cd, - 0xe11c9, - 0x11214b, - 0xe8188, - 0x643c9, - 0x10c246, - 0x228b03, - 0x9fe08, + 0x17e707, + 0x12380d, + 0xea609, + 0x115e0b, + 0xeec08, + 0x65dc9, + 0x111b86, + 0x308003, + 0x9a048, 0x9c4, - 0x11c3, - 0x2b05, - 0x9fe08, - 0xddc47, - 0x54c46, - 0x2b49, - 0x7b0e, - 0x14a647, + 0x4e83, + 0x68b05, + 0x9a048, + 0xe5a47, + 0x56306, + 0x68b49, + 0x1d134e, + 0x14a887, 0x2000c2, - 0x242244, - 0x20c302, - 0x22c0c3, - 0x201d02, - 0x232c43, - 0x14403, + 0x2d3684, + 0x201242, + 0x214a83, + 0x2052c2, + 0x232dc3, + 0x1bb43, 0x200382, - 0x2db1c4, - 0x214543, - 0x244502, - 0x20a803, + 0x2e3504, + 0x21bc83, + 0x201f42, + 0x21a3c3, + 0x30a42, 0x2003c2, - 0x216603, - 0x240986, - 0x332b0f, + 0x242543, + 0x2431c6, + 0x32d94f, 0x602, - 0x6be683, - 0x9fe08, - 0x20c302, - 0x212483, - 0x228b03, - 0x211543, - 0xca43, - 0x7b08, - 0x15c2c4b, - 0x15642ca, - 0xf5009, - 0x15c534a, - 0x150bb87, - 0xa4b0b, - 0x160745, - 0x116a49, - 0x12eb85, - 0x176c87, - 0xf3644, - 0x20c302, - 0x22c0c3, - 0x228b03, - 0x20a803, + 0x725e43, + 0x2f294a, + 0x9a048, + 0x201242, + 0x228503, + 0x308003, + 0x23c803, + 0x3dc3, + 0x1467206, + 0x1d1348, + 0x141650b, + 0x156518a, + 0xf1fc9, + 0x15d024a, + 0x1511707, + 0xa878b, + 0x10b7c5, + 0xebbc5, + 0x119bc9, + 0x139b05, + 0x17e707, + 0xfbfc4, + 0x201242, + 0x214a83, + 0x308003, + 0x21a3c3, 0x2000c2, 0x200c82, - 0x338dc2, - 0x12a2c0c3, - 0x23b182, - 0x232c43, - 0x2014c2, - 0x26bc02, - 0x228b03, - 0x220482, - 0x288542, - 0x22a402, + 0x2019c2, + 0x13214a83, + 0x23d342, + 0x232dc3, + 0x20bb42, + 0x2299c2, + 0x308003, + 0x23c782, + 0x25d282, + 0x22a742, 0x200cc2, - 0x291482, + 0x290602, 0x200802, 0x200d82, - 0x2033c2, - 0x21efc2, - 0x217d82, - 0xe550c, - 0x2b2182, - 0x2f10c2, - 0x215982, - 0x2450c2, - 0x211543, + 0x23ee42, + 0x27b8c2, + 0x204702, + 0x1b19cc, + 0x2b8e42, + 0x252e82, + 0x2203c2, + 0x248642, + 0x23c803, 0x200bc2, - 0x20a803, - 0x228c42, - 0x25b002, - 0x216603, - 0x301b82, - 0x209482, - 0x216002, - 0x203382, - 0x210342, - 0x2e8f82, - 0x214682, - 0x22b902, - 0x21e202, - 0x32370a, - 0x366b8a, - 0x39914a, - 0x3de682, - 0x20e6c2, - 0x3c3302, - 0x12fda689, - 0x1328caca, - 0x142d1c7, - 0x136049c2, - 0x14bd543, - 0x2482, - 0x8caca, - 0x15d14e, - 0x249f84, - 0xf04c5, - 0x13e2c0c3, - 0x3b903, - 0x232c43, - 0x24b304, - 0x228b03, - 0x224e44, - 0x214543, - 0x13bfc9, - 0x8f7c6, - 0x211543, - 0xe88c4, - 0x2143, - 0x20a803, - 0x12abc5, - 0x20ca43, - 0x216603, - 0x1429b04, - 0x236bc3, - 0x10cbc4, - 0x205b03, - 0x9fe08, - 0xbe5c6, - 0x14bdb84, - 0x146045, - 0x14a40a, - 0x12c5c2, - 0x1454114d, - 0x1a36c6, - 0x8f11, - 0x14bda689, - 0x1460c8, - 0x4aa08, - 0x1b584807, - 0x2282, - 0x1da807, - 0xe840e, - 0x12eb8b, - 0x13390b, - 0x1a3f4a, - 0x8824a, - 0x6bb47, - 0x9fe08, - 0x11a9c8, - 0x58c7, - 0x1b81684b, - 0x1ae07, - 0x9582, - 0x2b80d, - 0x13e387, - 0x14ebca, - 0x1ce74f, - 0x1732cf, - 0x8cac2, - 0xc302, - 0x84a08, - 0x1bcfdc4c, - 0xe1cca, - 0xdd74a, - 0x4f08a, - 0x1894c8, - 0xd948, - 0x59748, - 0xddc08, - 0xe7688, - 0x81c2, - 0x14db0f, - 0xa24cb, - 0x18a0c8, - 0x67607, - 0x168a, - 0x11404b, - 0x330c9, - 0x44447, - 0xd848, - 0x2e20c, - 0x16c307, - 0x5674a, - 0xe688, - 0x6aace, - 0x6b28e, - 0x6b98b, - 0x1d2e8b, - 0x1cb64b, - 0xe3089, - 0xead0b, - 0x3934d, - 0x3b98b, - 0x3c10d, - 0x3c48d, - 0x3de4a, - 0x4194b, - 0x461cb, - 0x44845, - 0x1c026590, - 0x19794f, - 0x13f50f, - 0x6a44d, - 0x13c190, - 0x9802, - 0x1c7d0408, - 0x114c8, - 0x93110, - 0x11d30e, - 0x1cb67ac5, - 0x4a80b, - 0x13b0d0, - 0x515c8, - 0xda4a, - 0x1d3049, - 0x60907, - 0x60c47, - 0x60e07, - 0x61787, - 0x62b87, - 0x63107, - 0x63b87, - 0x640c7, - 0x64d07, - 0x65087, - 0x65747, - 0x65907, + 0x21a3c3, + 0x243802, + 0x249b42, + 0x242543, + 0x308c82, + 0x2090c2, + 0x2023c2, + 0x202d42, + 0x207242, + 0x2f00c2, + 0x21e502, + 0x226dc2, + 0x223fc2, + 0x322c0a, + 0x36860a, + 0x39abca, + 0x3e0d02, + 0x210702, + 0x20ef42, + 0x1376fcc9, + 0x13b5cbca, + 0x142e307, + 0x13e026c2, + 0x14fe3c3, + 0x4a82, + 0x15cbca, + 0x15dc0e, + 0x24c0c4, + 0x572c5, + 0x14614a83, + 0x3dc83, + 0x232dc3, + 0x24d9c4, + 0x308003, + 0x221dc4, + 0x21bc83, + 0x137a89, + 0x68006, + 0x23c803, + 0xefa04, + 0x4743, + 0x21a3c3, + 0x1df105, + 0x203dc3, + 0x242543, + 0x1464b04, + 0x22b983, + 0x11b504, + 0x207783, + 0x9a048, + 0x1521403, + 0x125d86, + 0x1574504, + 0x68445, + 0x14a64a, + 0x129cc2, + 0x1500160d, + 0x1a6286, + 0x15291, + 0x1576fcc9, + 0x684c8, + 0x62888, + 0x1c12c707, + 0x1182, + 0x16fe47, + 0x2380e, + 0x139b0b, + 0x13f10b, + 0x1b3d4a, + 0x29907, + 0x9a048, + 0x11c988, + 0x7bc7, + 0x1c4169cb, + 0x1bf87, + 0xcd42, + 0x26ccd, + 0x1c2a07, + 0xaed8a, + 0x1d92cf, + 0x6738f, + 0x167c2, + 0x1242, + 0x83548, + 0x1c8f48cc, + 0xe770a, + 0xe554a, + 0x18990a, + 0x78508, + 0x8d08, + 0x5aa88, + 0xe5a08, + 0x145e88, + 0x2a42, + 0x1c464f, + 0xc134b, + 0x79108, + 0x25687, + 0x14474a, + 0x2490b, + 0x33249, + 0x46e07, + 0x8c08, + 0x3834c, + 0x15c087, + 0x1a67ca, + 0x106c8, + 0x2888e, + 0x2904e, + 0x2974b, + 0x2aa8b, + 0x15748b, + 0x14bf09, + 0xe3b0b, + 0xec58d, + 0x1261cb, + 0x30b4d, + 0x30ecd, + 0x3640a, + 0x3dd0b, + 0x3e54b, + 0x46405, + 0x1cd79a10, + 0x199e8f, + 0x9854f, + 0x63c4d, + 0x137c50, + 0xaac82, + 0x1d20c388, + 0xd1288, + 0xe8090, + 0xcf48e, + 0x1d75d105, + 0x4d1cb, + 0x136b90, + 0x8e0a, + 0x2ac49, + 0x61487, + 0x617c7, + 0x61987, + 0x61d07, + 0x631c7, + 0x63407, + 0x65587, 0x65ac7, - 0x65c87, - 0x664c7, - 0x67907, - 0x688c7, - 0x68c87, - 0x692c7, - 0x69587, - 0x69747, + 0x66007, + 0x66387, + 0x66a47, + 0x66c07, + 0x66dc7, + 0x66f87, 0x69a47, - 0x6be07, - 0x6c007, - 0x6cd87, - 0x6cf47, - 0x6d107, - 0x6f6c7, - 0x70a87, - 0x70f07, - 0x71647, - 0x71907, - 0x71c87, - 0x71e47, - 0x72247, - 0x72687, - 0x72a87, - 0x73007, - 0x731c7, - 0x73387, - 0x73c47, - 0x746c7, - 0x74c07, - 0x75207, - 0x753c7, - 0x75747, - 0x76847, - 0x4c02, - 0x5984a, - 0x13488, - 0x11a007, - 0x8a005, - 0xa7791, - 0x4886, - 0xfadca, - 0x8488a, - 0x54c46, - 0xacd8b, + 0x6a407, + 0x6ac07, + 0x6afc7, + 0x6b607, + 0x6b8c7, + 0x6ba87, + 0x6bd87, + 0x6c887, + 0x6ca87, + 0x6d907, + 0x6dac7, + 0x6dc87, + 0x6f247, + 0x71247, + 0x71707, + 0x72207, + 0x724c7, + 0x72847, + 0x72a07, + 0x72e07, + 0x73247, + 0x73707, + 0x73c87, + 0x73e47, + 0x74007, + 0x74447, + 0x74ec7, + 0x75407, + 0x75987, + 0x75b47, + 0x75ec7, + 0x76407, + 0x6882, + 0x5ab8a, + 0x11cc8, + 0x1b0ecc, + 0x71b87, + 0x85805, + 0xa7951, + 0x1c0d86, + 0xfb14a, + 0x833ca, + 0x56306, + 0xb060b, 0x642, - 0x2f451, - 0xb6fc9, - 0x97249, - 0x33c2, - 0x198c0a, - 0xaa289, - 0xaa9cf, - 0xaafce, - 0xac0c8, - 0x4742, - 0xbe0c9, - 0x1b0ece, - 0xea24c, - 0xf4d0f, - 0x1aeece, - 0x26ccc, - 0xe3389, - 0xe3911, - 0xe3ec8, - 0x2e612, - 0x17f34d, - 0x1a054d, - 0x4abcb, - 0x58415, - 0x6dc89, - 0x7280a, - 0x7a089, - 0x80510, - 0x16ff8b, - 0x1a798f, - 0x9110b, - 0x9494c, - 0x99310, - 0xa9a4a, - 0xadccd, - 0xaf68e, - 0xafdca, - 0xc4a8c, - 0xb42d4, - 0xb6c51, - 0xb8e0b, - 0xb9f0f, - 0xbb38d, - 0xbf5ce, - 0xc22cc, - 0xc3e0c, - 0xc478b, - 0xc558e, - 0xc6110, - 0xc7dcb, - 0x11c78d, - 0x141d4f, - 0x16d38c, - 0xcf38e, - 0xd1151, - 0xd564c, - 0xde6c7, - 0xf2b0d, - 0xfc10c, - 0x110450, - 0x1cc44d, - 0x105687, - 0x147410, - 0x166dc8, - 0x1710cb, - 0xb0d8f, - 0x1432c8, - 0xfafcd, - 0x10a190, - 0x176b89, - 0x1ceb2d46, - 0xb3cc3, - 0xb90c5, - 0x4e082, - 0x1b09, - 0x5590a, - 0x1d22eac6, - 0x1d73e584, - 0x56286, - 0x1dc4a, - 0x6f0cd, - 0x1d9b9b89, - 0x17c03, - 0x11594a, - 0xdb911, - 0xdbd49, - 0xdd6c7, - 0xde408, - 0xde887, - 0x11a0c8, - 0x908b, - 0x12e989, - 0xe9250, - 0xe970c, - 0xea548, - 0xea8c5, - 0x79148, - 0x10eaca, - 0xc7c07, - 0x523c7, - 0x2f42, - 0x1de46bd5, - 0x13bdca, - 0x3d888, - 0x98b89, - 0x2efc5, - 0x116b8a, - 0x8d04f, - 0x12b98b, - 0x1c340c, - 0x147952, - 0x78005, - 0x1966c8, - 0x4b60a, - 0x1e2f5b85, - 0x183acc, - 0x138c03, - 0x190ec6, - 0x3d182, - 0x10238b, - 0x102dca, - 0x150314c, - 0x11848, - 0x3c2c8, - 0x1e63d906, - 0x12fec7, - 0xa982, - 0x4e82, - 0x4bdd0, - 0x66647, - 0x2dccf, - 0x13686, - 0x15c7ce, - 0x9588b, - 0x45948, - 0x33489, - 0xfe992, - 0x190f8d, - 0x111788, - 0x112009, - 0x17ab8d, - 0x1964c9, - 0x1d714b, - 0x69bc8, - 0x7ea48, - 0x80908, - 0x80d49, - 0x80f4a, - 0x8730c, - 0x4648a, - 0xec2ca, - 0x110d47, - 0x9f70a, - 0x13670d, - 0xe41d1, - 0x1eabf8c6, - 0x1ab70b, - 0x12cfcc, - 0x37908, - 0x61249, - 0x15b14d, - 0x1a38d0, - 0x17b8cd, - 0x14302, - 0x5cd8d, - 0x5402, - 0x18d82, - 0x110c8a, - 0x1d4ca, - 0xfacca, - 0x11998b, - 0x6b50c, - 0x11a4ca, - 0x11a74e, - 0x1b318d, - 0x1edde545, - 0x1dae88, - 0x57c2, - 0x14e85c3, - 0x14ebec0e, - 0x156037ce, - 0x15e0254a, - 0x16745d0e, - 0x16e8f9ce, - 0x1772b10c, - 0x142d1c7, - 0x142d1c9, - 0x14bd543, - 0x17f6ae8c, - 0x186e7b09, - 0x18ef8849, - 0x1974a209, - 0x2482, - 0xbeb51, - 0x3711, - 0x248d, - 0x145c51, - 0x8f911, - 0x12b04f, - 0x16adcf, - 0xe7a4c, - 0xf878c, - 0x14a14c, - 0x1dc00d, - 0x1015d5, - 0x661cc, - 0x7394c, - 0x1bad50, - 0x130d4c, - 0x133fcc, - 0x155a59, - 0x162919, - 0x199999, - 0x1b67d4, - 0x1c41d4, - 0x1d09d4, - 0x5a54, - 0x6b54, - 0x19e66289, - 0x1a5d0c89, - 0x1ae73a09, - 0x152e40c9, - 0x2482, - 0x15ae40c9, - 0x2482, - 0x5a4a, - 0x2482, - 0x162e40c9, - 0x2482, - 0x5a4a, - 0x2482, - 0x16ae40c9, - 0x2482, - 0x172e40c9, - 0x2482, - 0x17ae40c9, - 0x2482, - 0x5a4a, - 0x2482, - 0x182e40c9, - 0x2482, - 0x5a4a, - 0x2482, - 0x18ae40c9, - 0x2482, - 0x192e40c9, - 0x2482, - 0x5a4a, - 0x2482, - 0x19ae40c9, - 0x2482, - 0x5a4a, - 0x2482, - 0x1a2e40c9, - 0x2482, - 0x1aae40c9, - 0x2482, - 0x1b2e40c9, - 0x2482, - 0x5a4a, - 0x2482, + 0x2f7d1, + 0xbf089, + 0x9b209, + 0x9bb06, + 0x3ee42, + 0x9218a, + 0xacdc9, + 0xad50f, + 0xadb0e, + 0xaff88, + 0x6502, + 0x174a49, + 0x8a58e, + 0x1c7f0c, + 0xf1ccf, + 0x1b7a0e, + 0x3230c, + 0x41a89, + 0xd2551, + 0xd2b08, + 0x59452, + 0x62a4d, + 0x733cd, + 0x7984b, + 0x7ea95, + 0xf0c09, + 0x182f8a, + 0x1a3749, + 0x1aa210, + 0x9028b, + 0x9378f, + 0xa694b, + 0xab54c, + 0xb1b90, + 0xb4b0a, + 0xcc00d, + 0xb7ece, + 0x14db0a, + 0x1bd50c, + 0xbe4d4, + 0xbed11, + 0xc0f0b, + 0xc310f, + 0xc5f8d, + 0xc854e, + 0xca80c, + 0xcb00c, + 0xcbd0b, + 0x13ea4e, + 0x16c350, + 0xd974b, + 0xda40d, + 0xdcf0f, + 0xdf00c, + 0xe648e, + 0xf2391, + 0x10498c, + 0x1dc387, + 0x10b44d, + 0x11a00c, + 0x140cd0, + 0x15fd8d, + 0x168847, + 0x18e8d0, + 0x19d508, + 0x1a160b, + 0xb6b8f, + 0x1b1148, + 0x149d4d, + 0x10f810, + 0x17e609, + 0x1db799c8, + 0x1deb9c06, + 0xbaac3, + 0x15a889, + 0xc00c5, + 0x1e42, + 0x144bc9, + 0x14a34a, + 0x1e259906, + 0x145990d, + 0x1e7c2c04, + 0x57a46, + 0x1e08a, + 0x6474d, + 0x1e9df489, + 0x19a83, + 0x1175ca, + 0xe4651, + 0xe4a89, + 0xe54c7, + 0xe61c8, + 0xe68c7, + 0x71c48, + 0x1540b, + 0x12bc49, + 0xf1210, + 0xf16cc, + 0xf27c8, + 0xf4705, + 0x13b1c8, + 0x1961ca, + 0x184947, + 0x2902, + 0x1ef47415, + 0x13788a, + 0x1b2589, + 0x108a08, + 0x9cd89, + 0x46145, + 0x119d0a, + 0x8decf, + 0x10b84b, + 0xf04c, + 0x18ee12, + 0x77285, + 0x114e48, + 0xf678b, + 0xe0a11, + 0x4dcca, + 0x1f2fe185, + 0x19b18c, + 0x133e43, + 0x192286, + 0x3fcc2, + 0x10948b, + 0x109f4a, + 0x150a2cc, + 0xd1608, + 0x30d08, + 0x1f708a86, + 0x1b2f07, + 0xca42, + 0x5142, + 0x18bb50, + 0x69bc7, + 0x2ee0f, + 0x11ec6, + 0x11ed0e, + 0x94c0b, + 0x472c8, + 0x33609, + 0x13ce92, + 0x19234d, + 0x115488, + 0x115cc9, + 0x176f4d, + 0x198609, + 0x63cb, + 0x6bf08, + 0x7a688, + 0x7ce08, + 0x7d249, + 0x7d44a, + 0x8c30c, + 0x3e80a, + 0xf198a, + 0x114cc7, + 0x9994a, + 0x1c350d, + 0xd2e11, + 0x1fac8846, + 0x1cd64b, + 0x97c4c, + 0x39988, + 0x13d849, + 0x15b84d, + 0x61f50, + 0x1808cd, + 0xc2c2, + 0x4f70d, + 0x1b82, + 0xc1c2, + 0x114c0a, + 0x6e70a, + 0xfb04a, + 0x10260b, + 0x292cc, + 0x11c48a, + 0x11c70e, + 0x1d74cd, + 0x1fde0bc5, + 0x128948, + 0x1442, + 0x14239c3, + 0x15a6960e, + 0x16204b4e, + 0x16a6820a, + 0x1734630e, + 0x17b63a8e, + 0x18289d0c, + 0x142e307, + 0x142e309, + 0x14fe3c3, + 0x18b0400c, + 0x1933dfc9, + 0x19b48e89, + 0x1a353b89, + 0x4a82, + 0x69551, + 0x4a91, + 0x6814d, + 0x146251, + 0x1639d1, + 0x89c4f, + 0x103f4f, + 0x13df0c, + 0x148dcc, + 0x153acc, + 0x4b5cd, + 0x1aaa15, + 0xedc8c, + 0x1b32cc, + 0x13f810, + 0x16b10c, + 0x178fcc, + 0x1ac319, + 0x1b6959, + 0x1c1259, + 0x1da294, + 0x76d4, + 0x7d54, + 0x9754, + 0x9f94, + 0x1aa07989, + 0x1b008009, + 0x1bbb3389, + 0x15ed2d09, + 0x4a82, + 0x166d2d09, + 0x4a82, + 0x76ca, + 0x4a82, + 0x16ed2d09, + 0x4a82, + 0x76ca, + 0x4a82, + 0x176d2d09, + 0x4a82, + 0x17ed2d09, + 0x4a82, + 0x186d2d09, + 0x4a82, + 0x76ca, + 0x4a82, + 0x18ed2d09, + 0x4a82, + 0x76ca, + 0x4a82, + 0x196d2d09, + 0x4a82, + 0x19ed2d09, + 0x4a82, + 0x76ca, + 0x4a82, + 0x1a6d2d09, + 0x4a82, + 0x76ca, + 0x4a82, + 0x1aed2d09, + 0x4a82, + 0x1b6d2d09, + 0x4a82, + 0x1bed2d09, + 0x4a82, + 0x76ca, + 0x4a82, 0x1400401, - 0x8f05, - 0x1a3f44, - 0x1442303, - 0x15b08c3, - 0x14ef043, - 0xbec0e, - 0x37ce, - 0x7984e, - 0x254a, - 0x145d0e, - 0x8f9ce, - 0x12b10c, - 0x16ae8c, - 0xe7b09, - 0xf8849, - 0x14a209, - 0x66289, - 0x1d0c89, - 0x73a09, - 0x1017cd, - 0x5d09, - 0x6e09, - 0x14c004, - 0x1a5104, - 0x1b3644, - 0x1b5344, - 0xa4dc4, - 0x1a82c4, - 0x35e04, - 0x50fc4, - 0x13584, - 0x1587c03, - 0xbe9c7, - 0x33d8c, - 0x13583, - 0x9802, - 0x10bb86, - 0x1b3183, - 0x13583, - 0x9bb83, - 0x3f02, - 0x3f08, - 0xdff47, - 0x12ea07, - 0x81c2, + 0x15285, + 0x1b3d44, + 0x14c86c3, + 0x15d6e03, + 0x14f8943, + 0x6960e, + 0x4b4e, + 0x7c80e, + 0x6820a, + 0x14630e, + 0x163a8e, + 0x89d0c, + 0x10400c, + 0x13dfc9, + 0x148e89, + 0x153b89, + 0x7989, + 0x8009, + 0x1b3389, + 0x13f8cd, + 0x9a09, + 0xa249, + 0x12f604, + 0x18ad44, + 0x1bad44, + 0x1bf004, + 0xa8a44, + 0x2cc04, + 0x3ca84, + 0x53684, + 0x11dc4, + 0x62b84, + 0x1588703, + 0x13dd87, + 0x147dc8c, + 0xf283, + 0xaac82, + 0xae8c6, + 0x1d74c3, + 0xf283, + 0x9fc83, + 0x8582, + 0x8588, + 0xe9247, + 0x12bcc7, + 0x2a42, 0x2000c2, - 0x20c302, - 0x201d02, - 0x20c202, + 0x201242, + 0x2052c2, + 0x20dec2, 0x200382, 0x2003c2, - 0x204e82, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x214383, - 0x20a803, - 0x216603, - 0x9fe08, - 0x22c0c3, - 0x232c43, - 0x20a803, - 0x216603, - 0x8503, - 0x228b03, - 0x24e44, + 0x205142, + 0x214a83, + 0x232dc3, + 0x308003, + 0x21bac3, + 0x21a3c3, + 0x242543, + 0x9a048, + 0x214a83, + 0x232dc3, + 0x21a3c3, + 0x242543, + 0xb2c3, + 0x308003, + 0x21dc4, 0x2000c2, - 0x248343, - 0x2122c0c3, - 0x38c507, - 0x228b03, - 0x20e403, - 0x217b84, - 0x20a803, - 0x216603, - 0x21de8a, - 0x240985, - 0x216103, - 0x219f82, - 0x9fe08, - 0x9fe08, - 0xc302, - 0x135f02, - 0x21bb990b, - 0x21e2c344, - 0x13e4c5, - 0x7d45, - 0xfdc46, - 0x22207d45, - 0x50cc3, - 0x93003, + 0x202703, + 0x22214a83, + 0x38b9c7, + 0x308003, + 0x21a8c3, + 0x219a04, + 0x21a3c3, + 0x242543, + 0x21e2ca, + 0x2431c5, + 0x2141c3, + 0x233442, + 0x9a048, + 0x226d8a4a, + 0xe01, + 0x9a048, + 0x1242, + 0x131a42, + 0x22fdf20b, + 0x23227fc4, + 0x1c2b45, + 0x1805, + 0xf48c6, + 0x23601805, + 0x53bc3, + 0x94e83, 0x9c4, - 0x11c3, - 0x2b05, - 0x12eb85, - 0x9fe08, - 0x1ae07, - 0x2c0c3, - 0x2c28d, - 0x22a380c7, - 0x15c6, - 0x22ce7945, - 0x1a9012, - 0x381c7, - 0xa0ca, - 0x9f88, - 0xe207, - 0x63d4a, - 0x18aec8, - 0x62607, - 0x18098f, - 0x43dc7, - 0x50dc6, - 0x13b0d0, - 0xc9fcf, - 0x20f09, - 0x56304, - 0x2303828e, - 0x11fb09, - 0x65dc6, - 0x109649, - 0x18ce06, - 0x1ba306, - 0x189e8c, - 0x11424a, - 0x33247, - 0x129b8a, - 0x143889, - 0xed38c, - 0x1ceb0a, - 0x7e54a, - 0x2b49, - 0x56286, - 0x3330a, - 0x11268a, - 0xa0d4a, - 0x127149, - 0xdad88, - 0xdb006, - 0xe208d, - 0xb9545, - 0x23754d4c, - 0x14a647, - 0x107849, - 0xa8c07, - 0x10a594, - 0x10aa8b, - 0x6744a, - 0xfe80a, - 0xa6d8d, - 0x1519b89, - 0x11154c, - 0x111e0b, - 0xe683, - 0xe683, - 0x39346, - 0xe683, - 0xfdc48, - 0x1581c3, - 0x33445, - 0x141d703, - 0x4e9c9, - 0x156d603, - 0x1439887, - 0x80787, - 0x245846c9, - 0xa6c6, - 0xbd389, - 0x48343, - 0x9fe08, - 0xc302, - 0x4b304, - 0x4243, - 0x4185, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x20a803, - 0x216603, - 0x225843, - 0x22c0c3, - 0x232c43, - 0x212483, - 0x228b03, - 0x211543, - 0x20a803, - 0x216603, - 0x297403, - 0x205b03, - 0x225843, - 0x242244, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x20a803, - 0x216603, - 0x21d0c3, - 0x261847c5, - 0x142bd43, - 0x22c0c3, - 0x232c43, - 0x214403, - 0x212483, - 0x228b03, - 0x224e44, - 0x201143, - 0x238cc3, - 0x211543, - 0x20a803, - 0x6d9c3, - 0x216603, - 0x216103, - 0x26e20643, - 0x147849, - 0xc302, - 0x2ff843, - 0x27a2c0c3, - 0x232c43, - 0x244743, - 0x228b03, - 0x217203, - 0x238cc3, - 0x216603, - 0x2f5cc3, - 0x3a4e04, - 0x9fe08, - 0x2822c0c3, - 0x232c43, - 0x2ac183, - 0x228b03, - 0x211543, - 0x217b84, - 0x20a803, - 0x216603, - 0x22d843, - 0x9fe08, - 0x28a2c0c3, - 0x232c43, - 0x212483, - 0x20ca43, - 0x216603, - 0x9fe08, - 0x142d1c7, - 0x248343, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x224e44, - 0x217b84, - 0x20a803, - 0x216603, - 0x12eb85, - 0x176c87, - 0x10a7cb, - 0xdc144, - 0xb9545, - 0x14470c8, - 0x2a20d, - 0x29e352c5, - 0x46e44, - 0xc302, - 0x8303, - 0x176a85, - 0x2d7c2, - 0x1dc2, - 0x2e7585, - 0x9fe08, - 0x7e42, - 0xeec3, - 0x16368f, - 0xc302, - 0xfcac6, + 0x4e83, + 0x68b05, + 0x139b05, + 0x9a048, + 0x1bf87, + 0x14a83, + 0x2cd0d, + 0x23e3a147, + 0x144686, + 0x24146145, + 0x1b8dd2, + 0x3a247, + 0x1d35ca, + 0x1d3488, + 0x95c7, + 0x6574a, + 0x1a7308, + 0xe2b07, + 0x1a870f, + 0x169347, + 0x53486, + 0x136b90, + 0x11dccf, + 0x1a009, + 0x57ac4, + 0x2443a30e, + 0x35509, + 0x670c6, + 0x10ecc9, + 0x18d986, + 0x1ba1c6, + 0x78ecc, + 0x24b0a, + 0x333c7, + 0x14420a, + 0x33c9, + 0xf714c, + 0x1d40a, + 0x5c30a, + 0x68b49, + 0x57a46, + 0x3348a, + 0x11634a, + 0xa430a, + 0x14fbc9, + 0xe30c8, + 0xe3346, + 0xeb54d, + 0x5390b, + 0xc0545, + 0x24b55a0c, + 0x14a887, + 0x10d1c9, + 0xbf407, + 0x10fc14, + 0x11010b, + 0x254ca, + 0x13cd0a, + 0xaabcd, + 0x1502809, + 0x11524c, + 0x115acb, + 0x106c3, + 0x106c3, + 0x28886, + 0x106c3, + 0xf48c8, + 0x155983, + 0x44ec4, + 0x53f83, + 0x335c5, + 0x146e943, + 0x50849, + 0xf678b, + 0x14df283, + 0x148406, + 0x14ecac7, + 0x1aa487, + 0x2592c5c9, + 0x1a286, + 0x173d09, + 0x2703, + 0x9a048, + 0x1242, + 0x4d9c4, + 0x88c3, + 0x8805, + 0x214a83, + 0x232dc3, + 0x308003, + 0x21a3c3, + 0x242543, + 0x220dc3, + 0x214a83, + 0x232dc3, + 0x228503, + 0x308003, + 0x23c803, + 0x21a3c3, + 0x242543, + 0x29b3c3, + 0x207783, + 0x220dc3, + 0x2d3684, + 0x214a83, + 0x232dc3, + 0x308003, + 0x21a3c3, + 0x242543, + 0x2308c3, + 0x2752c6c5, + 0x142c943, + 0x214a83, + 0x232dc3, + 0x21bb43, + 0x228503, + 0x308003, + 0x221dc4, + 0x2059c3, + 0x2137c3, + 0x23c803, + 0x21a3c3, + 0x1b4103, + 0x242543, + 0x2141c3, + 0x2821e9c3, + 0x18ed09, + 0x1242, + 0x3c0743, + 0x28e14a83, + 0x232dc3, + 0x247103, + 0x308003, + 0x223703, + 0x2137c3, + 0x242543, + 0x2f4bc3, + 0x3b9a84, + 0x9a048, + 0x29614a83, + 0x232dc3, + 0x2b0043, + 0x308003, + 0x23c803, + 0x219a04, + 0x21a3c3, + 0x242543, + 0x22e983, + 0x9a048, + 0x29e14a83, + 0x232dc3, + 0x228503, + 0x203dc3, + 0x242543, + 0x9a048, + 0x142e307, + 0x202703, + 0x214a83, + 0x232dc3, + 0x308003, + 0x221dc4, + 0x219a04, + 0x21a3c3, + 0x242543, + 0x139b05, + 0x17e707, + 0x10fe4b, + 0xe4e84, + 0xc0545, + 0x144ca88, + 0x2a54d, + 0x2b231ac5, + 0x647c4, + 0x1242, + 0x3a83, + 0x17e505, + 0x2aec2, + 0x5e42, + 0x303dc5, + 0x9a048, + 0x106c2, + 0x1d2c3, + 0x16454f, + 0x1242, + 0x105646, 0x2000c2, - 0x248343, - 0x22c0c3, - 0x228b03, - 0x224e44, - 0x211543, - 0x217b84, - 0x20a803, - 0x216603, - 0x216103, - 0x2d7c2, - 0x32d6c8, - 0x242244, - 0x342bc6, - 0x34a006, - 0x9fe08, - 0x31f443, - 0x20f509, - 0x3046d5, - 0x1046df, - 0x22c0c3, - 0x11d07, - 0x330912, - 0x170a46, - 0x17f0c5, - 0xda4a, - 0x1d3049, - 0x3306cf, - 0x2db1c4, - 0x28ed85, - 0x30b4d0, - 0x322e47, - 0x20ca43, - 0x31b008, - 0xf6f86, - 0x280aca, - 0x224d04, - 0x2f55c3, - 0x219f82, - 0x2eec0b, - 0xca43, - 0x17d404, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x211543, - 0x20a803, - 0xca43, - 0x216603, - 0x2fd643, - 0x20c302, - 0x12aec3, - 0x12a8c4, - 0x20a803, - 0x216603, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x211543, - 0x216603, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x20e403, - 0x22b0c3, - 0x216603, - 0x48343, - 0x20c302, - 0x22c0c3, - 0x232c43, - 0x20a803, - 0xca43, - 0x216603, + 0x202703, + 0x214a83, + 0x308003, + 0x221dc4, + 0x23c803, + 0x219a04, + 0x21a3c3, + 0x242543, + 0x2141c3, + 0x2aec2, + 0x32a988, + 0x2d3684, + 0x349646, + 0x353986, + 0x9a048, + 0x3373c3, + 0x2cd549, + 0x217915, + 0x1791f, + 0x214a83, + 0xd1ac7, + 0x214892, + 0x169046, + 0x1712c5, + 0x8e0a, + 0x2ac49, + 0x21464f, + 0x2e3504, + 0x224445, + 0x311050, + 0x2137c7, + 0x203dc3, + 0x31bf88, + 0x1283c6, + 0x27cfca, + 0x221c84, + 0x2fdbc3, + 0x233442, + 0x2f850b, + 0x3dc3, + 0x17cc84, + 0x214a83, + 0x232dc3, + 0x308003, + 0x23c803, + 0x21a3c3, + 0x3dc3, + 0x242543, + 0x306403, + 0x201242, + 0x89ac3, + 0x1dee04, + 0x21a3c3, + 0x242543, + 0x2ed73e05, + 0x8346, + 0x214a83, + 0x232dc3, + 0x308003, + 0x23c803, + 0x242543, + 0x214a83, + 0x232dc3, + 0x308003, + 0x21a8c3, + 0x223d43, + 0x242543, + 0x2703, + 0x201242, + 0x214a83, + 0x232dc3, + 0x21a3c3, + 0x3dc3, + 0x242543, + 0x267c2, 0x2000c2, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x20a803, - 0x216603, - 0x7d45, - 0x242244, - 0x22c0c3, - 0x232c43, - 0x303f84, - 0x20a803, - 0x216603, - 0x9fe08, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x20a803, - 0x6d9c3, - 0x216603, - 0x133d89, - 0x22c0c3, - 0x232c43, - 0x212483, - 0x204f43, - 0x211543, - 0x20a803, - 0xca43, - 0x216603, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x329144, - 0x224e44, - 0x20a803, - 0x216603, - 0x205b03, - 0x20c302, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x20a803, - 0x6d9c3, - 0x216603, - 0x9fe08, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x220383, - 0x63f43, - 0xe403, - 0x20a803, - 0x6d9c3, - 0x216603, - 0x32370a, - 0x3484c9, - 0x35f2cb, - 0x35f9ca, - 0x366b8a, - 0x378e4b, - 0x38cbca, - 0x39278a, - 0x39914a, - 0x3993cb, - 0x3b8049, - 0x3c840a, - 0x3c894b, - 0x3d5fcb, - 0x3dc90a, - 0x22c0c3, - 0x232c43, - 0x212483, - 0x211543, - 0x20a803, - 0xca43, - 0x216603, - 0x920b, - 0x5a448, - 0x17acc4, - 0x91c6, - 0x3e109, - 0x9fe08, - 0x22c0c3, - 0xda44, - 0x260904, - 0x20aa02, - 0x217b84, - 0x203045, - 0x225843, - 0x242244, - 0x22c0c3, - 0x235604, - 0x232c43, - 0x24b304, - 0x2db1c4, - 0x224e44, - 0x238cc3, - 0x20a803, - 0x216603, - 0x25cf45, - 0x21d0c3, - 0x216103, - 0x24f1c3, - 0x246484, - 0x2be544, - 0x2bd645, - 0x9fe08, - 0x344b04, - 0x3ba486, - 0x202c84, - 0x20c302, - 0x347d47, - 0x243647, - 0x249204, - 0x238a05, - 0x3cc645, - 0x22cd85, - 0x224e44, - 0x388dc8, - 0x3db706, - 0x32bec8, - 0x27c8c5, - 0x2e2a45, - 0x340644, - 0x216603, - 0x2f61c4, - 0x377bc6, - 0x240a83, - 0x246484, - 0x2411c5, - 0x201a84, - 0x336544, - 0x219f82, - 0x322706, - 0x3ab5c6, - 0x30df85, + 0x214a83, + 0x232dc3, + 0x308003, + 0x21a3c3, + 0x242543, + 0x1805, + 0xf283, + 0x2d3684, + 0x214a83, + 0x232dc3, + 0x306c44, + 0x21a3c3, + 0x242543, + 0x9a048, + 0x214a83, + 0x232dc3, + 0x308003, + 0x21a3c3, + 0x1b4103, + 0x242543, + 0x1b3089, + 0x29904, + 0x214a83, + 0x2a42, + 0x232dc3, + 0x228503, + 0x206c03, + 0x23c803, + 0x21a3c3, + 0x3dc3, + 0x242543, + 0x2982, + 0x214a83, + 0x232dc3, + 0x308003, + 0x343104, + 0x221dc4, + 0x21a3c3, + 0x242543, + 0x207783, + 0x16c2, + 0x201242, + 0x214a83, + 0x232dc3, + 0x308003, + 0x21a3c3, + 0x1b4103, + 0x242543, + 0x9a048, + 0x214a83, + 0x232dc3, + 0x308003, + 0x2f3983, + 0x13903, + 0x1a8c3, + 0x21a3c3, + 0x1b4103, + 0x242543, + 0x322c0a, + 0x3413c9, + 0x35fb0b, + 0x3602ca, + 0x36860a, + 0x377c8b, + 0x38d74a, + 0x39424a, + 0x39abca, + 0x39ae4b, + 0x3bcfc9, + 0x3ca20a, + 0x3ca58b, + 0x3d818b, + 0x3e040a, + 0x15702, + 0x214a83, + 0x232dc3, + 0x228503, + 0x23c803, + 0x21a3c3, + 0x3dc3, + 0x242543, + 0x1558b, + 0xcf487, + 0x5b788, + 0x177084, + 0x8f308, + 0xe8006, + 0x15546, + 0x366c9, + 0x9a048, + 0x214a83, + 0x8e04, + 0x261484, + 0x202742, + 0x219a04, + 0x269045, + 0x220dc3, + 0x2d3684, + 0x214a83, + 0x235b44, + 0x232dc3, + 0x24d9c4, + 0x2e3504, + 0x221dc4, + 0x2137c3, + 0x21a3c3, + 0x242543, + 0x24f8c5, + 0x2308c3, + 0x2141c3, + 0x32bf03, + 0x23e804, + 0x325d04, + 0x373fc5, + 0x9a048, + 0x203ac4, + 0x3b5cc6, + 0x268c84, + 0x201242, + 0x38f207, + 0x3a25c7, + 0x24b904, + 0x2e92c5, + 0x35ff85, + 0x22d805, + 0x221dc4, + 0x389208, + 0x22b586, + 0x3295c8, + 0x27b905, + 0x2ec0c5, + 0x262044, + 0x242543, + 0x2fe7c4, + 0x376806, + 0x2432c3, + 0x23e804, + 0x3829c5, + 0x344b44, + 0x23acc4, + 0x233442, + 0x231d86, + 0x3aeb46, + 0x313fc5, 0x2000c2, - 0x248343, - 0x3260c302, - 0x3d0584, + 0x202703, + 0x33e01242, + 0x20c504, 0x200382, - 0x211543, - 0x209082, - 0x20a803, + 0x23c803, + 0x215402, + 0x21a3c3, 0x2003c2, - 0x2f1d06, - 0x20c603, - 0x205b03, - 0x9fe08, - 0x9fe08, - 0x228b03, - 0x6d9c3, + 0x2fb406, + 0x20e2c3, + 0x207783, + 0x9a048, + 0x9a048, + 0x308003, + 0x1b4103, 0x2000c2, - 0x3320c302, - 0x228b03, - 0x2623c3, - 0x201143, - 0x22c344, - 0x20a803, - 0x216603, - 0x9fe08, + 0x34a01242, + 0x308003, + 0x266d43, + 0x2059c3, + 0x227fc4, + 0x21a3c3, + 0x242543, + 0x9a048, 0x2000c2, - 0x33a0c302, - 0x22c0c3, - 0x20a803, - 0xca43, - 0x216603, + 0x35201242, + 0x214a83, + 0x21a3c3, + 0x3dc3, + 0x242543, 0x682, - 0x206902, - 0x20ff42, - 0x20e403, - 0x2ed343, + 0x209d42, + 0x20c782, + 0x21a8c3, + 0x2f7103, 0x2000c2, - 0x12eb85, - 0x9fe08, - 0x176c87, - 0x20c302, - 0x232c43, - 0x24b304, - 0x2020c3, - 0x228b03, - 0x204f43, - 0x211543, - 0x20a803, - 0x213dc3, - 0x216603, - 0x233c43, - 0x1b8a13, - 0x127c94, - 0x12eb85, - 0x176c87, - 0x10f246, - 0x11b7cb, - 0x39346, - 0x531c7, - 0x38a06, + 0x139b05, + 0x9a048, + 0x17e707, + 0x201242, + 0x232dc3, + 0x24d9c4, + 0x207083, + 0x308003, + 0x206c03, + 0x23c803, + 0x21a3c3, + 0x2125c3, + 0x242543, + 0x233dc3, + 0x12be53, + 0x12e714, + 0x139b05, + 0x17e707, + 0x1d35c9, + 0x10d8c6, + 0xf5ecb, + 0x28886, + 0x54c47, + 0x15aec6, 0x649, - 0x160d4a, - 0x8984d, - 0x1263cc, - 0x11300a, - 0x45c88, - 0x175305, - 0xa108, - 0x13686, - 0x1be2c6, - 0x3e006, + 0x15794a, + 0x8b70d, + 0x12350c, + 0x116cca, + 0x112988, + 0x97805, + 0x1d3608, + 0x11ec6, + 0x1c6606, + 0x365c6, 0x602, - 0x209802, - 0x3b04, - 0x9bb86, - 0x184410, - 0x8170e, - 0x2846, - 0x1841cc, - 0x3537314b, - 0x12eb85, - 0x1426cb, - 0x357be204, - 0x1a4107, - 0x25191, - 0x11f54a, - 0x22c0c3, - 0x63cc5, - 0x1bd708, - 0x12704, - 0x55b05, - 0x3588c906, - 0xa7786, - 0xc14c6, - 0x9174a, - 0x1a8883, - 0x35e0bfc4, - 0x4e9c9, - 0x12c047, - 0x1770a, - 0x14ce3c9, + 0x2aac82, + 0x174ec4, + 0x9fc86, + 0x12c310, + 0x147498e, + 0x68846, + 0x6264c, + 0x36a6720b, + 0x139b05, + 0x14820b, + 0x36fc6544, + 0x1b3f07, + 0x22111, + 0x1ae28a, + 0x214a83, + 0x3727db88, + 0x656c5, + 0x19b808, + 0xca04, + 0x14a545, + 0x3755ca06, + 0xa7946, + 0xc7746, + 0x908ca, + 0x1b5c43, + 0x37a0dc84, + 0x50849, + 0x129747, + 0x1274ca, + 0x14d8949, 0x605, - 0xeac83, - 0x3622eb47, - 0x12abc5, - 0x153c6c6, - 0x153f846, - 0xace4c, - 0xfa308, - 0x3643d183, - 0xeee4b, - 0x118a4b, - 0x36a4528c, - 0x14070c3, - 0xbb048, - 0xef0c5, - 0xa2349, - 0x119c88, - 0x141db86, - 0x88147, - 0x36f5b149, - 0x117787, - 0x16074a, - 0x111acd, - 0x8148, - 0x13583, - 0xbdb03, - 0xfdc48, - 0x13584, - 0x1224c5, - 0x148d103, - 0xe85c7, - 0x372e85c3, - 0x377afc46, - 0x37af67c4, - 0x37f02f87, - 0xfdc44, - 0xfdc44, - 0xfdc44, - 0xfdc44, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x211543, - 0x20a803, - 0x216603, + 0xec503, + 0x37e33f07, + 0x1df105, + 0x1538186, + 0x1498886, + 0xb06cc, + 0x101b88, + 0x3803fcc3, + 0xf874b, + 0x13864b, + 0x38647c0c, + 0x140a503, + 0xc2dc8, + 0xf89c5, + 0xc11c9, + 0xea803, + 0x102908, + 0x141dfc6, + 0x86107, + 0x38b5b849, + 0x19d887, + 0xebbca, + 0x39fbf648, + 0x11578d, + 0xa788, + 0xf283, + 0x1443f09, + 0x174483, + 0x28886, + 0xf48c8, + 0x11dc4, + 0x1205c5, + 0x148df83, + 0x239c7, + 0x38e239c3, + 0x393c0a06, + 0x39637f04, + 0x39b0a107, + 0xf48c4, + 0xf48c4, + 0xf48c4, + 0xf48c4, + 0x41, + 0x214a83, + 0x232dc3, + 0x308003, + 0x23c803, + 0x21a3c3, + 0x242543, 0x2000c2, - 0x20c302, - 0x228b03, - 0x203dc2, - 0x20a803, - 0x216603, - 0x20c603, - 0x37fe4f, - 0x38020e, - 0x9fe08, - 0x22c0c3, - 0x41487, - 0x232c43, - 0x228b03, - 0x214543, - 0x20a803, - 0x216603, - 0x2784, - 0x1304, - 0x144444, - 0x21c0c3, - 0x374247, - 0x206082, - 0x26c3c9, + 0x201242, + 0x308003, + 0x206182, + 0x21a3c3, + 0x242543, + 0x20e2c3, + 0x3810cf, + 0x38148e, + 0x9a048, + 0x214a83, + 0x43bc7, + 0x232dc3, + 0x308003, + 0x21bc83, + 0x21a3c3, + 0x242543, + 0x68784, + 0x4fc4, + 0x145bc4, + 0x21c9c3, + 0x296747, + 0x203082, + 0x26ce49, 0x200ac2, - 0x24c0cb, - 0x29d88a, - 0x29e589, + 0x38be4b, + 0x2a1b8a, + 0x2a2889, 0x200542, - 0x212ac6, - 0x38d7d5, - 0x24c215, - 0x231e53, - 0x24c793, - 0x212082, - 0x21e405, - 0x369e0c, - 0x27494b, - 0x297885, - 0x202542, - 0x299082, - 0x37bf46, - 0x202282, - 0x37bb46, - 0x20dccd, - 0x32a94c, - 0x226604, + 0x20cdc6, + 0x236a55, + 0x38bf95, + 0x2391d3, + 0x38c513, + 0x2037c2, + 0x2037c5, + 0x2037cc, + 0x27514b, + 0x276205, + 0x204b42, + 0x29d282, + 0x37bb86, + 0x201182, + 0x2c9d46, + 0x20908d, + 0x3dee8c, + 0x379a84, 0x200882, - 0x20be02, - 0x22e9c8, + 0x202b02, + 0x259808, 0x200202, - 0x30e386, - 0x30e38f, - 0x393f90, - 0x21f204, - 0x38d995, - 0x231fd3, - 0x21cf83, - 0x349d0a, - 0x208b87, - 0x369349, - 0x2175c7, - 0x227682, + 0x205086, + 0x395a8f, + 0x205090, + 0x3a1544, + 0x236c15, + 0x239353, + 0x24d2c3, + 0x34934a, + 0x214f07, + 0x383d89, + 0x327387, + 0x220f82, 0x200282, - 0x3b4e46, - 0x203c02, - 0x9fe08, - 0x208082, - 0x208342, - 0x21e9c7, - 0x330307, - 0x330311, - 0x218585, - 0x21858e, - 0x21968f, - 0x209582, - 0x373907, - 0x21c708, - 0x205b82, - 0x2c1142, - 0x21bb46, - 0x21bb4f, - 0x269f10, - 0x22a8c2, - 0x204042, - 0x251c88, - 0x204043, - 0x25c6c8, - 0x2db50d, - 0x2094c3, - 0x3bc3c8, - 0x27f40f, - 0x27f7ce, - 0x2fe4ca, - 0x2da0d1, - 0x2da550, - 0x2dc90d, - 0x2dcc4c, - 0x2ff6c7, - 0x349e87, - 0x342c89, - 0x226702, - 0x201ec2, - 0x2553cc, - 0x2556cb, + 0x3beb06, + 0x205fc2, + 0x9a048, + 0x202e82, + 0x201542, + 0x20ac47, + 0x36a6c7, + 0x36a6d1, + 0x2180c5, + 0x2180ce, + 0x218e8f, + 0x20cd42, + 0x2679c7, + 0x21d008, + 0x207682, + 0x21d482, + 0x2101c6, + 0x2101cf, + 0x263710, + 0x22c042, + 0x2086c2, + 0x238c48, + 0x2086c3, + 0x25cec8, + 0x2c1bcd, + 0x215843, + 0x363208, + 0x27fc4f, + 0x28000e, + 0x33c9ca, + 0x2f5211, + 0x2f5690, + 0x300acd, + 0x300e0c, + 0x24a147, + 0x3494c7, + 0x349709, + 0x220f42, + 0x204342, + 0x25678c, + 0x256a8b, 0x200d42, - 0x2c4946, - 0x202c82, + 0x2cbec6, + 0x20b682, 0x200482, - 0x28cac2, - 0x20c302, - 0x22c784, - 0x237d87, - 0x22ae02, - 0x23cbc7, - 0x23ed47, - 0x22e002, - 0x22dac2, - 0x241345, - 0x259dc2, - 0x382a4e, - 0x3c91cd, - 0x232c43, - 0x28658e, - 0x3d234d, - 0x32fe43, - 0x202102, - 0x284744, - 0x24a542, - 0x2253c2, - 0x39b645, - 0x39ce07, - 0x243f82, - 0x20c202, - 0x24af07, - 0x24ed48, - 0x2b12c2, - 0x278086, - 0x25524c, - 0x25558b, - 0x203d42, - 0x25d0cf, - 0x25d490, - 0x25d88f, - 0x25dc55, - 0x25e194, - 0x25e68e, - 0x25ea0e, - 0x25ed8f, - 0x25f14e, - 0x25f4d4, - 0x25f9d3, - 0x25fe8d, - 0x276a09, - 0x28b243, - 0x2020c2, - 0x35c2c5, - 0x3cfd46, + 0x2167c2, + 0x201242, + 0x22d204, + 0x239e07, + 0x22ba02, + 0x23f707, + 0x241247, + 0x22f142, + 0x22ec02, + 0x243a85, + 0x205582, + 0x392dce, + 0x3cae0d, + 0x232dc3, + 0x28508e, + 0x2b794d, + 0x328b03, + 0x2027c2, + 0x21fc84, + 0x24cf02, + 0x222342, + 0x38cdc5, + 0x39d187, + 0x246702, + 0x20dec2, + 0x24d5c7, + 0x250bc8, + 0x22dec2, + 0x277306, + 0x25660c, + 0x25694b, + 0x205dc2, + 0x25db0f, + 0x25ded0, + 0x25e2cf, + 0x25e695, + 0x25ebd4, + 0x25f0ce, + 0x25f44e, + 0x25f7cf, + 0x25fb8e, + 0x25ff14, + 0x260413, + 0x2608cd, + 0x2765c9, + 0x28d003, + 0x207082, + 0x31e805, + 0x3ddc86, 0x200382, - 0x3776c7, - 0x228b03, + 0x37f147, + 0x308003, 0x200642, - 0x231448, - 0x2da311, - 0x2da750, - 0x202b82, - 0x28a387, - 0x201742, - 0x247f07, - 0x24e082, - 0x328c49, - 0x37bf07, - 0x296c48, - 0x28c746, - 0x28f303, - 0x28f305, - 0x21d702, + 0x361608, + 0x2f5451, + 0x2f5890, + 0x201f02, + 0x28bf47, + 0x204582, + 0x271547, + 0x201e42, + 0x295749, + 0x37bb47, + 0x29ac08, + 0x35c846, + 0x24b083, + 0x24b085, + 0x233042, 0x2004c2, - 0x3b5245, - 0x383f45, - 0x201b02, - 0x22aec3, - 0x342a47, - 0x20c907, - 0x201f82, - 0x201f84, - 0x20e503, - 0x2ebf89, - 0x20e508, - 0x203102, - 0x205f82, - 0x2eb887, - 0x3dd285, - 0x33fb88, - 0x34e347, - 0x21a7c3, - 0x29ba06, - 0x2dc78d, - 0x2dcb0c, - 0x2d5d46, - 0x204b02, - 0x21fc02, - 0x206a42, - 0x27f28f, - 0x27f68e, - 0x3cc6c7, - 0x206702, - 0x295d05, - 0x295d06, - 0x21d902, + 0x3bef05, + 0x39b605, + 0x202482, + 0x21bdc3, + 0x348587, + 0x20e5c7, + 0x201842, + 0x345044, + 0x210543, + 0x31d809, + 0x210548, + 0x202042, + 0x208282, + 0x2ed207, + 0x2f5145, + 0x298bc8, + 0x2ae507, + 0x20fac3, + 0x29fb06, + 0x30094d, + 0x300ccc, + 0x305086, + 0x206782, + 0x2017c2, + 0x209e82, + 0x27facf, + 0x27fece, + 0x360007, + 0x210942, + 0x372385, + 0x372386, + 0x21d542, 0x200bc2, - 0x28d746, - 0x2062c3, - 0x206586, - 0x2cc185, - 0x2cc18d, - 0x2cc7d5, - 0x2cd88c, - 0x2cdc0d, - 0x2cdf52, - 0x205a02, - 0x26bf42, - 0x2050c2, - 0x3dbec6, - 0x3b0d86, - 0x202f42, - 0x3cfdc6, - 0x218d42, - 0x374a45, - 0x202f82, - 0x382b89, - 0x22330c, - 0x22364b, + 0x28e5c6, + 0x247703, + 0x3c5d46, + 0x2d6705, + 0x2d670d, + 0x2d6f95, + 0x2d7e0c, + 0x2d818d, + 0x2d84d2, + 0x202382, + 0x26c9c2, + 0x202802, + 0x219386, + 0x3c7dc6, + 0x202902, + 0x3ddd06, + 0x206e42, + 0x296f45, + 0x201582, + 0x392f09, + 0x21ae0c, + 0x21b14b, 0x2003c2, - 0x24f708, - 0x201902, + 0x251d88, + 0x202942, 0x200a82, - 0x271f86, - 0x2e4045, + 0x272b46, + 0x2d2c85, 0x200a87, - 0x228445, - 0x2563c5, - 0x2091c2, - 0x20a1c2, - 0x2161c2, - 0x3a7c87, - 0x2f1dcd, - 0x2f214c, - 0x243047, - 0x278002, - 0x201c82, - 0x3c63c8, - 0x201c88, - 0x32c1c8, - 0x2faf84, - 0x2c5807, - 0x33e603, - 0x223c42, - 0x212842, - 0x2f3749, - 0x26aec7, - 0x216102, - 0x272385, - 0x220082, - 0x20b182, - 0x2fd083, - 0x2fd086, - 0x2fd202, - 0x301b02, + 0x227c85, + 0x257145, + 0x215542, + 0x2a3882, + 0x214282, + 0x293a87, + 0x2fb4cd, + 0x2fb84c, + 0x234307, + 0x277282, + 0x205742, + 0x3d2508, + 0x344d48, + 0x3298c8, + 0x3b1104, + 0x33ecc7, + 0x3c2c83, + 0x21b742, + 0x20cb42, + 0x2fc0c9, + 0x228c87, + 0x2141c2, + 0x272f45, + 0x214b42, + 0x20eb42, + 0x2f6e43, + 0x2f6e46, + 0x305fc2, + 0x308c02, 0x200402, - 0x36c686, - 0x2aba07, - 0x215f02, + 0x35c406, + 0x21fbc7, + 0x213fc2, 0x200902, - 0x25c50f, - 0x2863cd, - 0x3b12ce, - 0x3d21cc, - 0x204bc2, - 0x203d82, - 0x28c585, - 0x320886, + 0x25cd0f, + 0x284ecd, + 0x28a98e, + 0x2b77cc, + 0x206842, + 0x206142, + 0x35c685, + 0x320b86, 0x200b82, - 0x204d42, + 0x2069c2, 0x200682, - 0x286744, - 0x2db384, - 0x359786, - 0x204e82, - 0x286e87, - 0x23bc03, - 0x23bc08, - 0x23f748, - 0x37f1c7, - 0x24e306, - 0x201702, - 0x2183c3, - 0x2183c7, - 0x314946, - 0x2e7e85, - 0x2fb308, - 0x202602, - 0x3a9687, - 0x2411c2, - 0x293042, - 0x209442, - 0x219809, + 0x285244, + 0x2c1a44, + 0x384486, + 0x205142, + 0x27a207, + 0x23d903, + 0x23d908, + 0x23e108, + 0x2d23c7, + 0x24c186, + 0x207842, + 0x20b603, + 0x20b607, + 0x3a6dc6, + 0x2ee0c5, + 0x274608, + 0x2071c2, + 0x3b9447, + 0x26c702, + 0x294ec2, + 0x206382, + 0x205249, 0x201082, - 0xc41c8, - 0x2021c2, - 0x2432c3, - 0x202247, - 0x205c42, - 0x22348c, - 0x22378b, - 0x2d5dc6, - 0x2eabc5, - 0x247c82, - 0x201942, - 0x2bf146, - 0x236483, - 0x328ec7, - 0x235282, + 0xcb3c8, + 0x203882, + 0x234583, + 0x204847, + 0x203282, + 0x21af8c, + 0x21b28b, + 0x305106, + 0x2ec445, + 0x202c02, + 0x202982, + 0x2c55c6, + 0x216643, + 0x342e87, + 0x291f82, 0x2008c2, - 0x38d655, - 0x24c3d5, - 0x231d13, - 0x24c913, - 0x37f647, - 0x25b951, - 0x262d10, - 0x274d92, - 0x2779d1, - 0x284bc8, - 0x284bd0, - 0x2d7c8f, - 0x29d653, - 0x29e352, - 0x29ffd0, - 0x2a7b8f, - 0x2a9e12, - 0x305811, - 0x371353, - 0x3b78d2, - 0x2b2e8f, - 0x2cbe0e, - 0x2cd412, - 0x2d3c51, - 0x2d430f, - 0x2d830e, - 0x2d9791, - 0x2de010, - 0x2df0d2, - 0x2e8a91, - 0x2ef5d0, - 0x2fa4cf, - 0x2fd6d1, - 0x3029d0, - 0x31bb46, - 0x3adfc7, - 0x20ce47, - 0x201a42, - 0x2824c5, - 0x30b247, - 0x20ff42, - 0x207e02, - 0x229545, - 0x220883, - 0x2bdfc6, - 0x2f1f8d, - 0x2f22cc, - 0x217042, - 0x369c8b, - 0x27480a, - 0x21e2ca, - 0x2bc0c9, - 0x2f0c0b, - 0x34e48d, - 0x30b94c, - 0x25b3ca, - 0x27108c, - 0x2758cb, - 0x2976cc, - 0x31ce0e, - 0x36710b, - 0x2b1d4c, - 0x2e2703, - 0x37aa86, - 0x3bcb02, - 0x2fbb02, - 0x25a083, - 0x20ff82, - 0x233b03, - 0x324b86, - 0x25de07, - 0x2e0e06, - 0x2e1e88, - 0x3428c8, - 0x31d5c6, + 0x2368d5, + 0x38c155, + 0x239093, + 0x38c693, + 0x24ee47, + 0x26ee11, + 0x275590, + 0x283712, + 0x2eb111, + 0x29a208, + 0x29a210, + 0x29f38f, + 0x2a1953, + 0x2a2652, + 0x2a7d50, + 0x2b4ecf, + 0x3689d2, + 0x3a1891, + 0x3d4d53, + 0x2b9d52, + 0x2d634f, + 0x2ddd0e, + 0x2e1112, + 0x2e1fd1, + 0x2e5e0f, + 0x2e7c8e, + 0x2efbd1, + 0x2f8ed0, + 0x301d52, + 0x306491, + 0x309b50, + 0x311f8f, + 0x3cea91, + 0x347910, + 0x37b006, + 0x380cc7, + 0x218987, + 0x209f42, + 0x280f85, + 0x310dc7, + 0x20c782, + 0x2018c2, + 0x229e45, + 0x21ec03, + 0x374946, + 0x2fb68d, + 0x2fb9cc, + 0x203642, + 0x20364b, + 0x27500a, + 0x22408a, + 0x2c43c9, + 0x2fa74b, + 0x2ae64d, + 0x3114cc, + 0x35d58a, + 0x244f8c, + 0x27188b, + 0x27604c, + 0x29b68e, + 0x2bf90b, + 0x2b8a0c, + 0x2dc483, + 0x376e46, + 0x3bf642, + 0x304382, + 0x24f4c3, + 0x206482, + 0x20c3c3, + 0x324506, + 0x25e847, + 0x352386, + 0x2e78c8, + 0x348408, + 0x2cf746, 0x200f02, - 0x30d94d, - 0x30dc8c, - 0x318c07, - 0x312e47, - 0x229942, - 0x216302, - 0x218342, - 0x279642, - 0x335056, - 0x33a4d5, - 0x33d6d6, - 0x346693, - 0x346d52, - 0x357d53, - 0x358492, - 0x3aa4cf, - 0x3bbb18, - 0x3bc5d7, - 0x3bdc19, - 0x3be7d8, - 0x3bf698, - 0x3c46d7, - 0x3c57d7, - 0x3c7016, - 0x3ca6d3, - 0x3cbc95, - 0x3cc992, - 0x3cce13, - 0x20c302, - 0x20a803, - 0x216603, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x211543, - 0x217b84, - 0x20a803, - 0x216603, - 0x20c603, + 0x31398d, + 0x313ccc, + 0x338807, + 0x316b07, + 0x234a42, + 0x2143c2, + 0x20b582, + 0x27c602, + 0x330496, + 0x335f95, + 0x3395d6, + 0x33ff53, + 0x340612, + 0x355513, + 0x358152, + 0x3acc8f, + 0x3be558, + 0x3bf117, + 0x3bfc59, + 0x3c1898, + 0x3c3c58, + 0x3c5fd7, + 0x3c6b17, + 0x3c8216, + 0x3cc693, + 0x3ccfd5, + 0x3cdd52, + 0x3ce1d3, + 0x201242, + 0x21a3c3, + 0x242543, + 0x214a83, + 0x232dc3, + 0x308003, + 0x23c803, + 0x219a04, + 0x21a3c3, + 0x242543, + 0x20e2c3, 0x2000c2, - 0x203042, - 0x39e946c5, - 0x3a219305, - 0x3a675c06, - 0x9fe08, - 0x3aab3405, - 0x20c302, - 0x201d02, - 0x3aefedc5, - 0x3b280405, - 0x3b681c47, - 0x3ba82949, - 0x3bf064c4, + 0x201602, + 0x3be933c5, + 0x3c281445, + 0x3c746bc6, + 0x9a048, + 0x3caba385, + 0x201242, + 0x2052c2, + 0x3ce871c5, + 0x3d27e985, + 0x3d680387, + 0x3da806c9, + 0x3de1f844, 0x200382, 0x200642, - 0x3c25aec5, - 0x3c6998c9, - 0x3cb34708, - 0x3ceafc45, - 0x3d313987, - 0x3d622508, - 0x3db11985, - 0x3de9a406, - 0x3e243789, - 0x3e6d1dc8, - 0x3eac45c8, - 0x3ee99f0a, - 0x3f277244, - 0x3f605285, - 0x3fac0b08, - 0x3fe01885, - 0x213ec2, - 0x40242a83, - 0x406a64c6, - 0x40b4f408, - 0x40e1f986, - 0x412dd348, - 0x41779b06, - 0x41a3f204, - 0x41e05642, - 0x427315c7, - 0x42aacb84, - 0x42e79cc7, - 0x433c4d87, + 0x3e249a05, + 0x3e69d789, + 0x3eb2fb48, + 0x3eeb4985, + 0x3f350107, + 0x3f61d988, + 0x3fb09745, + 0x3fe9e2c6, + 0x403a2709, + 0x406db0c8, + 0x40aca648, + 0x40e9ddca, + 0x412c21c4, + 0x4168e885, + 0x41ac6c08, + 0x41f44945, + 0x20fe82, + 0x42297703, + 0x426aa1c6, + 0x42aaf5c8, + 0x42ef2f86, + 0x4320ad88, + 0x43785546, + 0x43a02c44, + 0x43e08482, + 0x446f4cc7, + 0x44ab0b04, + 0x44e79487, + 0x453cfc87, 0x2003c2, - 0x4369e985, - 0x43a88bc4, - 0x43ed0e07, - 0x4423b747, - 0x44684586, - 0x44a81485, - 0x44e999c7, - 0x452d1c48, - 0x457c5107, - 0x45b48289, - 0x45ed3985, - 0x463102c7, - 0x46693d06, - 0x46e4b, - 0x46a7b288, - 0x2221cd, - 0x27d049, - 0x28858b, - 0x2aa48b, - 0x2b734b, - 0x31368b, - 0x320a8b, - 0x320d4b, - 0x321b89, - 0x32398b, - 0x323c4b, - 0x32430b, - 0x32548a, - 0x3259ca, - 0x325fcc, - 0x32bc4b, - 0x32c3ca, - 0x3419ca, - 0x34d0ce, - 0x35024e, - 0x3505ca, - 0x3521ca, - 0x352bcb, - 0x352e8b, - 0x353b0b, - 0x36d78b, - 0x36dd8a, - 0x36ea4b, - 0x36ed0a, - 0x36ef8a, - 0x36f20a, - 0x38decb, - 0x39360b, - 0x395ace, - 0x395e4b, - 0x39cfcb, - 0x39de8b, - 0x3a124a, - 0x3a14c9, - 0x3a170a, - 0x3a31ca, - 0x3bb50b, - 0x3c8c0b, - 0x3c960a, - 0x3ca10b, - 0x3d38cb, - 0x3dc34b, - 0x46e82f08, - 0x47288fc9, - 0x476a21c9, - 0x47ae4d08, - 0x359505, - 0x218e03, - 0x27e244, - 0x2abc05, - 0x306206, - 0x34d545, - 0x288844, - 0x3775c8, - 0x3197c5, - 0x295604, - 0x3c17c7, - 0x2a154a, - 0x381fca, - 0x3cc7c7, - 0x218d07, - 0x2de547, - 0x282bc7, - 0x35e6c5, - 0x3b0106, - 0x3b0347, - 0x3bdb04, - 0x2f1246, - 0x2f1146, - 0x3b06c5, - 0x355784, - 0x29af46, - 0x2a0607, - 0x26a746, - 0x31f207, - 0x27e303, - 0x39c446, - 0x251ec5, - 0x281d47, - 0x267aca, - 0x231544, - 0x220c88, - 0x310809, - 0x2cc587, - 0x38f346, - 0x28ee48, - 0x2200c9, - 0x369504, - 0x35c644, - 0x2d5085, - 0x225d48, - 0x2ca407, - 0x2f3249, - 0x228ec8, - 0x315686, - 0x229a46, - 0x29b888, - 0x371b06, - 0x219305, - 0x284646, - 0x27a648, - 0x27f186, - 0x25440b, - 0x292ec6, - 0x29d1cd, - 0x3c12c5, - 0x2aca46, - 0x210985, - 0x3b91c9, - 0x249507, - 0x3a4a48, - 0x314486, - 0x29c489, - 0x3b8486, - 0x267a45, - 0x215146, - 0x2c9006, - 0x2cee49, - 0x2b9b06, - 0x2a1247, - 0x2a4385, - 0x207683, - 0x223cc5, - 0x2affc7, - 0x36a486, - 0x3c11c9, - 0x275c06, - 0x279ec6, - 0x21a549, - 0x284049, - 0x2a4907, - 0x344e08, - 0x2a75c9, - 0x282148, - 0x3929c6, - 0x2dab45, - 0x278eca, - 0x279f46, - 0x21ce06, - 0x2d28c5, - 0x24ff08, - 0x2eb407, - 0x22f24a, - 0x24bb06, - 0x2f4745, - 0x302086, - 0x328687, - 0x38f207, - 0x21b145, - 0x267c05, - 0x269d86, - 0x26e4c6, - 0x27fdc6, - 0x226384, - 0x2835c9, - 0x28a146, - 0x2fd3ca, - 0x2278c8, - 0x30ffc8, - 0x381fca, - 0x223fc5, - 0x2a0545, - 0x3c1e08, - 0x2bcc08, - 0x266e07, - 0x226b86, - 0x338748, - 0x20e887, - 0x2815c8, - 0x2b8cc6, - 0x285308, - 0x298406, - 0x27ca47, - 0x3229c6, - 0x29af46, - 0x26ed4a, - 0x2d5ec6, - 0x2dab49, - 0x368506, - 0x21eb0a, - 0x23f209, - 0x2f2786, - 0x2baac4, - 0x35c38d, - 0x289247, - 0x2e6186, - 0x2c4485, - 0x3b8505, - 0x38fe46, - 0x2d0c49, - 0x2b7907, - 0x27bb46, - 0x2c9e46, - 0x2888c9, - 0x359a44, - 0x244f84, - 0x340e88, - 0x236846, - 0x2a3e08, - 0x2150c8, - 0x219447, - 0x3b5b89, - 0x27ffc7, - 0x2b32ca, - 0x2f420f, - 0x26f44a, - 0x28c385, - 0x27a885, - 0x214f05, - 0x21f147, - 0x267083, - 0x345008, - 0x20ef06, - 0x20f009, - 0x3cb186, - 0x2d0487, - 0x29c249, - 0x3a4948, - 0x2d2987, - 0x31da43, - 0x359585, - 0x3281c5, - 0x2261cb, - 0x201944, - 0x308804, - 0x278686, - 0x31dc07, - 0x39abca, - 0x242b07, - 0x2ff907, - 0x280405, - 0x3bfc85, - 0x26de89, - 0x29af46, - 0x24298d, - 0x33fac5, - 0x2b6243, - 0x23ffc3, - 0x3d0605, - 0x35e345, - 0x28ee48, - 0x27c487, - 0x244d06, - 0x2a1e46, - 0x229e05, - 0x232f07, - 0x2e6d07, - 0x3db5c7, - 0x20530a, - 0x39c508, - 0x226384, - 0x27ef07, - 0x27ec47, - 0x353106, - 0x297a87, - 0x2e0388, - 0x360f08, - 0x249406, - 0x218f48, - 0x2b9b84, - 0x3b0346, - 0x238786, - 0x3aa006, - 0x345606, - 0x219cc4, - 0x282c86, - 0x2c3106, - 0x29b306, - 0x22f846, - 0x3c6986, - 0x2e01c6, - 0x244c08, - 0x2b4d08, - 0x2d6848, - 0x34d748, - 0x3c1d86, - 0x209a85, - 0x223c86, - 0x2afcc5, - 0x391e47, - 0x228f85, - 0x20ba83, - 0x20ca85, - 0x230fc4, - 0x3c6ac5, - 0x201903, + 0x456a2c85, + 0x45a13504, + 0x45fa3407, + 0x4623d187, + 0x466830c6, + 0x46a7f445, + 0x46e9d887, + 0x472daf48, + 0x477d0007, + 0x47b41189, + 0x47ed7505, + 0x48331207, + 0x48692a06, + 0x647cb, + 0x48b3aec8, + 0x225bcd, + 0x25d2c9, + 0x27418b, + 0x27c08b, + 0x2b014b, + 0x2f010b, + 0x320d8b, + 0x32104b, + 0x321e89, + 0x322e8b, + 0x32314b, + 0x323c8b, + 0x324e0a, + 0x32534a, + 0x32594c, + 0x32934b, + 0x329aca, + 0x33e6ca, + 0x34b30e, + 0x34d44e, + 0x34d7ca, + 0x34f64a, + 0x350c0b, + 0x350ecb, + 0x3519cb, + 0x36cdcb, + 0x36d3ca, + 0x36e08b, + 0x36e34a, + 0x36e5ca, + 0x36e84a, + 0x38e64b, + 0x39510b, + 0x397c0e, + 0x397f8b, + 0x39e8cb, + 0x39fc0b, + 0x3a3fca, + 0x3a4249, + 0x3a448a, + 0x3a5d8a, + 0x3bdf4b, + 0x3ca84b, + 0x3cb24a, + 0x3cc0cb, + 0x3d520b, + 0x3dfe4b, + 0x48e81788, + 0x4928ae89, + 0x496a5789, + 0x49aed408, + 0x3597c5, + 0x2041c3, + 0x251084, + 0x3015c5, + 0x21f586, + 0x307385, + 0x28a004, + 0x37f048, + 0x31bb05, + 0x294984, + 0x3c7607, + 0x2a4b0a, + 0x38f4ca, + 0x360107, + 0x34c207, + 0x2e6307, + 0x280947, + 0x334605, + 0x3b9b46, + 0x2f2207, + 0x39bc04, + 0x2f9b46, + 0x2f9a46, + 0x3c2d85, + 0x3b6684, + 0x29ee06, + 0x2a3bc7, + 0x34bb86, + 0x3adf47, + 0x251143, + 0x384106, + 0x238e85, + 0x280487, + 0x26a5ca, + 0x356504, + 0x219d88, + 0x31a2c9, + 0x2d4847, + 0x390606, + 0x3c5808, + 0x2f36c9, + 0x383f44, + 0x31eb84, + 0x2dea45, + 0x222b48, + 0x2d4b07, + 0x36c9c9, + 0x34cdc8, + 0x318406, + 0x264a46, + 0x29f988, + 0x36b706, + 0x281445, + 0x283186, + 0x279b88, + 0x27f9c6, + 0x255d8b, + 0x39d746, + 0x2a14cd, + 0x3d0845, + 0x2b09c6, + 0x20c045, + 0x24a789, + 0x370447, + 0x385188, + 0x291386, + 0x2a0689, + 0x3b1306, + 0x26a545, + 0x2a6dc6, + 0x2e5346, + 0x2d9209, + 0x2c0b06, + 0x2a4807, + 0x360b05, + 0x201583, + 0x21b7c5, + 0x34dd07, + 0x288f46, + 0x3d0749, + 0x346bc6, + 0x279686, + 0x20f849, + 0x282b89, + 0x2a8587, + 0x343488, + 0x2a7789, + 0x280c08, + 0x394486, + 0x2e2e85, + 0x2cfd8a, + 0x279706, + 0x33a806, + 0x2dc705, + 0x2523c8, + 0x326447, + 0x22f5ca, + 0x24e1c6, + 0x2e05c5, + 0x309186, + 0x215f87, + 0x3904c7, + 0x21c2c5, + 0x26a705, + 0x263586, + 0x269d46, + 0x26c0c6, + 0x2c70c4, + 0x282109, + 0x28bd06, + 0x30618a, + 0x2211c8, + 0x330f08, + 0x38f4ca, + 0x2af785, + 0x2a3b05, + 0x3c4f48, + 0x2c4f08, + 0x237c47, + 0x3b9d86, + 0x333988, + 0x2108c7, + 0x274848, + 0x2bebc6, + 0x283ec8, + 0x29c606, + 0x27ba87, + 0x3681c6, + 0x29ee06, + 0x2643ca, + 0x305206, + 0x2e2e89, + 0x36f506, + 0x2a5c8a, + 0x202c49, + 0x241706, + 0x2c2844, + 0x31e8cd, + 0x28b107, + 0x3b2a86, + 0x2ca505, + 0x3b1385, + 0x391106, + 0x2a7349, + 0x2bd687, + 0x27ab86, + 0x31db46, + 0x28a089, + 0x281384, + 0x244744, + 0x204088, + 0x356846, + 0x2a6ec8, + 0x318a88, + 0x2883c7, + 0x3c0549, + 0x26c2c7, + 0x2ba24a, + 0x2fcb8f, + 0x2e43ca, + 0x3d9e45, + 0x279dc5, + 0x2173c5, + 0x3c2147, + 0x215b43, + 0x343688, + 0x3de2c6, + 0x3de3c9, + 0x2f2b06, + 0x2d9047, + 0x2a0449, + 0x385088, + 0x2dc7c7, + 0x31f203, + 0x359845, + 0x215ac5, + 0x2c6f0b, + 0x344a04, + 0x23ba44, + 0x277906, + 0x31f3c7, + 0x39168a, + 0x3803c7, + 0x293607, + 0x27e985, + 0x3c8785, + 0x270489, + 0x29ee06, + 0x38024d, + 0x298b05, + 0x2bc683, + 0x226283, + 0x35c505, + 0x334285, + 0x3c5808, + 0x27b4c7, + 0x2444c6, + 0x2a5406, + 0x22a145, + 0x233087, + 0x287ec7, + 0x22b447, + 0x28e90a, + 0x3841c8, + 0x2c70c4, + 0x27f747, + 0x27d6c7, + 0x35e406, + 0x29bc87, + 0x2e9688, + 0x357b08, + 0x370346, + 0x34c448, + 0x2c0b84, + 0x2f2206, + 0x37ff46, + 0x3bbc46, + 0x204506, + 0x2a3044, + 0x280a06, + 0x2c95c6, + 0x29f1c6, + 0x245806, + 0x3d0d46, + 0x2e94c6, + 0x2443c8, + 0x2bb748, + 0x2dfcc8, + 0x307588, + 0x3c4ec6, + 0x206a05, + 0x21b786, + 0x2b4a05, 0x393907, - 0x36d1c8, - 0x31f2c6, - 0x376e0d, - 0x27a846, - 0x29a8c5, - 0x219803, - 0x2c04c9, - 0x359bc6, - 0x296206, - 0x398b84, - 0x26f3c7, - 0x36c186, - 0x2b7bc5, - 0x242943, - 0x3d7004, - 0x27ee06, - 0x238884, - 0x2e9f88, - 0x3befc9, - 0x309209, - 0x2a3c0a, - 0x2a54cd, - 0x2318c7, - 0x3ba1c6, - 0x20a204, - 0x282949, - 0x287b88, - 0x288e46, - 0x234b46, - 0x297a87, - 0x2c1246, - 0x34fc46, - 0x2ffa86, - 0x3c4e0a, - 0x222508, - 0x2e3805, - 0x33e9c9, - 0x2cab8a, - 0x305288, - 0x29f1c8, - 0x296188, - 0x2e710c, - 0x350805, - 0x2a20c8, - 0x2b5006, - 0x317646, - 0x3d8287, - 0x242a05, - 0x2847c5, - 0x3090c9, - 0x20ac07, - 0x20efc5, - 0x237187, - 0x23ffc3, - 0x2cb045, - 0x21ac08, - 0x283347, - 0x29f089, - 0x2dedc5, - 0x3ae2c4, - 0x2a5188, - 0x331707, - 0x2d2b48, - 0x3d36c8, - 0x2adbc5, - 0x21f506, - 0x249886, - 0x2d5449, - 0x2b3f47, - 0x2b0386, - 0x3d00c7, - 0x205083, - 0x3064c4, - 0x2d8c85, - 0x233044, - 0x248d84, - 0x3890c7, - 0x2651c7, - 0x27bd04, - 0x29eed0, - 0x33ebc7, - 0x3bfc85, - 0x2f764c, - 0x32a2c4, - 0x2b2b48, - 0x27c949, - 0x385146, - 0x319dc8, - 0x270d84, - 0x278988, - 0x331dc6, - 0x26ebc8, - 0x2a0bc6, - 0x2d004b, - 0x32de45, - 0x2d8b08, - 0x213304, - 0x3bf40a, - 0x29f089, - 0x3228c6, - 0x225fc8, - 0x258305, - 0x2bfd44, - 0x2b2a46, - 0x3db488, - 0x282f08, - 0x338fc6, - 0x301104, - 0x278e46, - 0x280047, - 0x279bc7, - 0x297a8f, - 0x32eec7, - 0x2f2847, - 0x295bc5, - 0x376185, - 0x2a45c9, - 0x2d7886, - 0x389305, - 0x284347, - 0x2cd008, - 0x2f9c05, - 0x3229c6, - 0x227708, - 0x21f98a, - 0x3db188, - 0x28d4c7, - 0x2f4646, - 0x33e986, - 0x2003c3, - 0x208a43, - 0x2cad49, - 0x2a7449, - 0x2b2946, - 0x2dedc5, - 0x2191c8, - 0x225fc8, - 0x371c88, - 0x2ffb0b, - 0x377047, - 0x31ae49, - 0x297d08, - 0x351c84, - 0x3a9c48, - 0x290cc9, - 0x2b0685, - 0x21f047, - 0x306545, - 0x282e08, - 0x29454b, - 0x299710, - 0x2ac685, - 0x21324c, - 0x244ec5, - 0x280483, - 0x31cc06, - 0x2c2644, - 0x288cc6, - 0x2a0607, - 0x212bc4, - 0x23ffc8, - 0x344ecd, - 0x31c485, - 0x231904, - 0x2a3484, - 0x2a3489, - 0x2af088, - 0x32e307, - 0x331e48, - 0x283688, - 0x27be45, - 0x2110c7, - 0x27bdc7, - 0x20f2c7, - 0x267c09, - 0x2e6809, - 0x3c3b86, - 0x2dce46, - 0x284406, - 0x323fc5, - 0x3af9c4, + 0x29d485, + 0x20d743, + 0x226305, + 0x2ed004, + 0x3d0e85, + 0x202943, + 0x395407, + 0x36c188, + 0x3ae006, + 0x37e88d, + 0x279d86, + 0x29e785, + 0x205243, + 0x2c65c9, + 0x281506, + 0x299486, + 0x292104, + 0x2e4347, + 0x35bf06, + 0x244945, + 0x23a8c3, + 0x206284, + 0x27d886, + 0x35ad44, + 0x26e588, + 0x3c7989, + 0x2bdc09, + 0x2a6cca, + 0x2a914d, + 0x361a87, + 0x3ba086, + 0x2afb04, + 0x2806c9, + 0x285b48, + 0x28ad06, + 0x234e86, + 0x29bc87, + 0x2c74c6, + 0x2261c6, + 0x287346, + 0x3cfd0a, + 0x21d988, + 0x265085, + 0x295e09, + 0x2d528a, + 0x30b048, + 0x2a34c8, + 0x299408, + 0x2b0d0c, + 0x34da05, + 0x2a5688, + 0x2bba46, + 0x372046, + 0x3db607, + 0x3802c5, + 0x283305, + 0x2bdac9, + 0x20d447, + 0x3de385, + 0x2283c7, + 0x226283, + 0x2d5745, + 0x2273c8, + 0x2d6d07, + 0x2a3389, + 0x2e2d45, + 0x380fc4, + 0x2a8e08, + 0x2c1e87, + 0x2dc988, + 0x20d188, + 0x2b1a85, + 0x20c206, + 0x2a5506, + 0x2dee09, + 0x380047, + 0x2b52c6, + 0x3de007, + 0x2027c3, + 0x21f844, + 0x2da0c5, + 0x2331c4, + 0x246744, + 0x389507, + 0x2664c7, + 0x27ad44, + 0x2a31d0, + 0x296007, + 0x3c8785, + 0x30394c, + 0x20cf44, + 0x2b9a08, + 0x27b989, 0x3bcb46, - 0x3bed86, - 0x27be88, - 0x32834b, - 0x2363c7, - 0x20a204, - 0x36c0c6, - 0x2e06c7, - 0x3da1c5, - 0x374cc5, - 0x227c84, - 0x2e6786, - 0x3bcbc8, - 0x282949, - 0x264806, - 0x287988, - 0x2b7c86, - 0x35d948, - 0x32170c, - 0x27bd06, - 0x29a58d, - 0x29aa0b, - 0x2a1305, - 0x2e6e47, - 0x2b9c06, - 0x38f0c8, - 0x3c3c09, - 0x307e48, - 0x3bfc85, - 0x3bd847, - 0x282248, - 0x3c0bc9, - 0x36be06, - 0x26470a, - 0x38ee48, - 0x307c8b, - 0x22278c, - 0x278a88, - 0x27e846, - 0x210ac8, - 0x21f607, - 0x21ca09, - 0x3983cd, - 0x29ae46, - 0x267048, - 0x2b4bc9, - 0x2c0f48, - 0x285408, - 0x2c3b4c, - 0x2c5107, - 0x2c5bc7, - 0x267a45, - 0x2c0d87, - 0x2ccec8, - 0x2b2ac6, - 0x2934cc, - 0x2f9688, - 0x2d1588, - 0x234d86, - 0x34ef07, - 0x3c3d84, - 0x34d748, - 0x28688c, - 0x289b8c, - 0x28c405, - 0x3b0747, - 0x301086, - 0x34ee86, - 0x3b9388, - 0x21c984, - 0x26a74b, - 0x286fcb, - 0x2f4646, - 0x344d47, - 0x28f405, - 0x271a45, - 0x26a886, - 0x2582c5, - 0x201905, - 0x2cec87, - 0x20afc9, - 0x26e684, - 0x258e45, - 0x2fcfc5, - 0x2e9d08, - 0x28b9c5, - 0x2bd109, - 0x2b3947, - 0x2b394b, - 0x2f24c6, - 0x244949, - 0x3556c8, - 0x291005, - 0x20f3c8, - 0x2e6848, - 0x261fc7, - 0x331bc7, - 0x389149, - 0x26eb07, - 0x29cf89, - 0x2fc3cc, - 0x348188, - 0x2b9649, - 0x2bb207, - 0x283749, - 0x2ff287, - 0x222888, - 0x3b5d45, - 0x3b02c6, - 0x2c44c8, - 0x2d7148, - 0x2caa49, - 0x201947, - 0x272445, - 0x336b09, - 0x2d3206, - 0x293d04, - 0x31bf86, - 0x34f288, - 0x3cbac7, - 0x328548, - 0x219009, - 0x2f8107, - 0x2a1706, - 0x2e6f04, - 0x20cb09, - 0x210f48, - 0x234c47, - 0x36b6c6, - 0x328286, - 0x21cd84, - 0x2f5206, - 0x20f0c3, - 0x32d9c9, - 0x32de06, - 0x2accc5, - 0x2a1e46, - 0x2cf205, - 0x2826c8, - 0x20edc7, - 0x238ec6, - 0x2fee06, - 0x30ffc8, - 0x2a4747, - 0x29ae85, - 0x29ecc8, - 0x3a77c8, - 0x38ee48, - 0x244d85, - 0x3b0346, - 0x308fc9, - 0x2d52c4, - 0x2cf08b, - 0x34f94b, - 0x2e3709, - 0x23ffc3, - 0x256085, - 0x2e48c6, - 0x245b08, - 0x304204, - 0x31f2c6, - 0x205449, - 0x2c2f05, - 0x2cebc6, - 0x331706, - 0x2191c4, - 0x29f34a, - 0x2acc08, - 0x2d7146, - 0x3c2785, - 0x344bc7, - 0x35e587, - 0x21f504, - 0x34fb87, - 0x228f44, - 0x228f46, - 0x20eb03, - 0x267c05, - 0x2b1045, - 0x32f108, - 0x27f0c5, - 0x27ba49, - 0x2a62c7, - 0x34d58b, - 0x2a62cc, - 0x2a68ca, - 0x313987, - 0x20cc43, - 0x3897c8, - 0x244f45, - 0x2f9c85, - 0x359644, - 0x222786, - 0x27c946, - 0x2f5247, - 0x33608b, - 0x219cc4, - 0x3ac004, - 0x2c9a44, - 0x2ce986, - 0x212bc4, - 0x225e48, - 0x359445, - 0x21afc5, - 0x371bc7, - 0x2e6f49, - 0x35e345, - 0x38fe4a, - 0x2a4289, - 0x2ae38a, - 0x3c4f49, - 0x352404, - 0x2c9f05, - 0x2c1348, - 0x2d0ecb, - 0x2d5085, - 0x215246, - 0x209744, - 0x27bf86, - 0x2f7f89, - 0x2e07c7, - 0x275dc8, - 0x2a5846, - 0x27ffc7, - 0x282f08, - 0x3903c6, - 0x3bd204, - 0x380547, - 0x36fe85, - 0x382607, - 0x29a404, - 0x2b9b86, - 0x304f88, - 0x29abc8, - 0x2f1887, - 0x31d6c8, - 0x2984c5, - 0x240004, - 0x381ec8, - 0x295e04, - 0x214e85, - 0x305184, - 0x20e987, - 0x28a207, - 0x283888, - 0x2d2cc6, - 0x27f045, - 0x27b848, - 0x248e88, - 0x2a3b49, - 0x34fc46, - 0x22f2c8, - 0x3bf28a, - 0x3da248, - 0x311985, - 0x223e86, - 0x2a4148, - 0x3bd90a, - 0x20d487, - 0x287fc5, - 0x293f08, - 0x2ab804, - 0x24ff86, - 0x2c5f48, - 0x3c6986, - 0x3c9c88, - 0x254747, - 0x3c16c6, - 0x2baac4, - 0x266847, - 0x2b5684, - 0x2f7f47, - 0x36bacd, - 0x266e85, - 0x2d0a4b, - 0x289e06, - 0x24f808, - 0x23ff84, - 0x3c1f86, - 0x27ee06, - 0x210e07, - 0x29a24d, - 0x2fbf87, - 0x2b6188, - 0x285585, - 0x26e048, - 0x2ca386, - 0x298548, - 0x22e4c6, - 0x2f73c7, - 0x283c09, - 0x35a447, - 0x289108, - 0x273d85, - 0x229e88, - 0x34edc5, - 0x26b045, - 0x34c4c5, - 0x215183, - 0x2846c4, - 0x294105, - 0x243789, - 0x36b5c6, - 0x2e0488, - 0x331985, - 0x2b7f47, - 0x3171ca, - 0x2ceb09, - 0x2c8f0a, - 0x2d68c8, - 0x236fcc, - 0x2843cd, - 0x30ad03, - 0x3c9b88, - 0x3d6fc5, - 0x21f746, - 0x3a47c6, - 0x35c045, - 0x3d01c9, - 0x28e9c5, - 0x27b848, - 0x257506, - 0x360146, - 0x2a5049, - 0x3a6787, - 0x294806, - 0x317148, - 0x3a9f08, - 0x2e4f07, - 0x2c328e, - 0x2ca5c5, - 0x3c0ac5, - 0x3c6888, - 0x31a307, - 0x200e42, - 0x2c36c4, - 0x288bca, - 0x234d08, - 0x2e6986, - 0x29c388, - 0x249886, - 0x36a0c8, - 0x2b0388, - 0x26b004, - 0x2b8705, - 0x602c84, - 0x602c84, - 0x602c84, - 0x204ec3, - 0x328106, - 0x27bd06, - 0x2a0fcc, - 0x202f03, - 0x2cab86, - 0x21a9c4, - 0x359b48, - 0x205285, - 0x288cc6, - 0x2c0c08, - 0x2d8046, - 0x238e46, - 0x212bc8, - 0x2d8d07, - 0x26e8c9, - 0x32044a, - 0x2052c4, - 0x228f85, - 0x2f3205, - 0x3598c6, - 0x231906, - 0x2a1b06, - 0x3cc306, - 0x26ea04, - 0x26ea0b, - 0x228d44, - 0x244ac5, - 0x2af585, - 0x219506, - 0x3c6e08, - 0x284287, - 0x32dd84, - 0x25a2c3, - 0x2ab305, - 0x31be47, - 0x28418b, - 0x32f007, - 0x2c0b08, - 0x2bf447, - 0x269406, - 0x27d308, - 0x292a0b, - 0x2abb46, - 0x213a89, - 0x292b85, - 0x31da43, - 0x2cebc6, - 0x254648, - 0x214303, - 0x27d903, - 0x27b386, - 0x249886, - 0x37880a, - 0x27e885, - 0x27ec4b, - 0x2a1d8b, - 0x244043, - 0x206743, - 0x2b3244, - 0x249647, - 0x2546c4, - 0x219344, - 0x2b4e84, - 0x3da548, - 0x3c26c8, - 0x2089c9, - 0x2d3a08, + 0x302a48, + 0x267884, + 0x277c08, + 0x22fbc6, + 0x264248, + 0x2a4186, + 0x28ba4b, + 0x32b105, + 0x2d9f48, + 0x211b44, + 0x281e8a, + 0x2a3389, + 0x3680c6, + 0x2bbc48, + 0x259345, + 0x2c5bc4, + 0x2b9906, + 0x22b308, + 0x281788, + 0x32dc86, + 0x384404, + 0x2cfd06, + 0x26c347, + 0x279387, + 0x29bc8f, + 0x339e47, + 0x2417c7, + 0x372245, + 0x372ac5, + 0x2a8249, + 0x2ead06, + 0x389745, + 0x282e87, + 0x3db888, + 0x300805, + 0x3681c6, + 0x221008, + 0x2f2f8a, + 0x22b008, + 0x28e347, + 0x2fcfc6, + 0x295dc6, + 0x2003c3, + 0x212503, + 0x2d5449, + 0x2a7609, + 0x2b9806, + 0x2e2d45, + 0x2b0b88, + 0x2bbc48, + 0x36b888, + 0x2873cb, + 0x37eac7, + 0x31bdc9, + 0x29bf08, + 0x34f104, + 0x3bb888, + 0x28fe49, + 0x2b55c5, + 0x3c2047, + 0x21f8c5, + 0x281688, + 0x29324b, + 0x29d5d0, + 0x2b0545, + 0x211a8c, + 0x244685, + 0x27ea03, + 0x2bf706, + 0x2c8b04, + 0x368486, + 0x2a3bc7, + 0x202804, + 0x242808, + 0x34354d, + 0x318845, + 0x2a2cc4, + 0x2ae044, + 0x2b3e49, + 0x2b2308, + 0x32b5c7, + 0x22fc48, + 0x2821c8, + 0x27ae85, + 0x2d0e87, + 0x27ae07, + 0x2cd307, + 0x26a709, + 0x2879c9, + 0x3dfb46, + 0x301006, + 0x282f46, + 0x322605, + 0x3b8a04, + 0x3c4206, + 0x3c7086, + 0x27aec8, + 0x215c4b, + 0x3563c7, + 0x2afb04, + 0x35be46, + 0x2e99c7, + 0x36f805, + 0x2971c5, + 0x2ae204, + 0x287946, + 0x3c4288, + 0x2806c9, + 0x24bb46, + 0x285948, + 0x244a06, + 0x360a48, + 0x321a0c, + 0x27ad46, + 0x29e44d, + 0x29e8cb, + 0x2a48c5, + 0x288007, + 0x2c0c06, + 0x390388, + 0x3dfbc9, + 0x2ee4c8, + 0x3c8785, + 0x39b947, + 0x280d08, + 0x23b4c9, + 0x35bb86, + 0x25138a, + 0x390108, + 0x2ee30b, + 0x21dc0c, + 0x277d08, + 0x27cc06, + 0x2d0888, + 0x2f2c07, + 0x33a409, + 0x35024d, + 0x29ed06, + 0x2250c8, + 0x2bb609, + 0x2c71c8, + 0x283fc8, + 0x2c9ecc, + 0x2cab87, + 0x2cb7c7, + 0x26a545, + 0x2bdf87, + 0x3db748, + 0x2b9986, + 0x24b9cc, + 0x300288, + 0x2db2c8, + 0x307846, + 0x2af0c7, + 0x3dfd44, + 0x307588, + 0x2cf84c, + 0x28538c, + 0x3d9ec5, + 0x3c2e07, + 0x384386, + 0x2af046, + 0x24a948, + 0x21d284, + 0x34bb8b, + 0x27a34b, + 0x2fcfc6, + 0x3433c7, + 0x343ec5, + 0x272605, + 0x34bcc6, + 0x259305, + 0x3449c5, + 0x2d4287, + 0x20e989, + 0x269f04, + 0x25a2c5, + 0x2f6d85, + 0x35aac8, + 0x28d785, + 0x2cf209, + 0x2badc7, + 0x2badcb, + 0x2fbbc6, + 0x244109, + 0x3b65c8, + 0x290185, + 0x2cd408, + 0x287a08, + 0x253047, + 0x2b4247, + 0x389589, + 0x264187, + 0x29d389, + 0x2da70c, + 0x341088, + 0x2c0649, + 0x2c2f87, + 0x282289, + 0x33c3c7, + 0x21dd08, + 0x33a345, + 0x2f2186, + 0x2ca548, + 0x217488, + 0x2d5149, + 0x344a07, + 0x273005, + 0x3c3909, + 0x2f42c6, + 0x292a04, + 0x37b446, + 0x2af448, + 0x320807, + 0x215e48, + 0x34c509, + 0x33be47, + 0x2a4cc6, + 0x2880c4, + 0x226389, + 0x2d0d08, + 0x307707, + 0x367a06, + 0x215b86, + 0x33a784, + 0x34c706, + 0x239f83, + 0x32ac89, + 0x32b0c6, + 0x2a3705, + 0x2a5406, + 0x2d95c5, + 0x281188, + 0x347207, + 0x2306c6, + 0x287206, + 0x330f08, + 0x2a83c7, + 0x29ed45, + 0x2a2fc8, + 0x3aa048, + 0x390108, + 0x244545, + 0x2f2206, + 0x2bd9c9, + 0x2dec84, + 0x2d944b, + 0x225ecb, + 0x264f89, + 0x226283, + 0x257845, + 0x3ae4c6, + 0x246508, + 0x306ec4, + 0x3ae006, + 0x28ea49, + 0x2c93c5, + 0x2d41c6, + 0x2c1e86, + 0x222dc4, + 0x29958a, + 0x2a3648, + 0x217486, + 0x2cd045, + 0x343d47, + 0x3344c7, + 0x20c204, + 0x226107, + 0x2ba244, + 0x34ce46, + 0x210b43, + 0x26a705, + 0x2b6e45, + 0x23ef88, + 0x27f905, + 0x27aa89, + 0x2a9fc7, + 0x3073cb, + 0x2a9fcc, + 0x2aa5ca, + 0x350107, + 0x203d03, + 0x278808, + 0x244705, + 0x300885, + 0x359904, + 0x21dc06, + 0x27b986, 0x34c747, - 0x22f846, - 0x2e00cf, - 0x2ca706, - 0x2d6044, - 0x3c250a, - 0x31bd47, - 0x2b5786, - 0x293d49, - 0x208945, - 0x32f245, - 0x208a86, - 0x229fc3, - 0x2ab849, - 0x222686, - 0x218dc9, - 0x39abc6, - 0x267c05, - 0x28c805, - 0x206643, - 0x249788, - 0x32e4c7, - 0x20ef04, - 0x3599c8, - 0x3173c4, - 0x356506, - 0x31cc06, - 0x23b486, - 0x2d89c9, - 0x2f9c05, - 0x29af46, - 0x247d89, - 0x2c9646, - 0x2e01c6, - 0x39f786, - 0x212185, - 0x305186, - 0x2f73c4, - 0x3b5d45, - 0x2c44c4, - 0x2b6b06, - 0x33fa84, - 0x201a43, - 0x287c45, - 0x233c08, - 0x3d2cc7, - 0x304289, - 0x287ec8, - 0x29b651, - 0x33178a, - 0x2f4587, - 0x254886, - 0x21a9c4, - 0x2c45c8, - 0x2b5c48, - 0x29b80a, - 0x2bcecd, - 0x215146, - 0x212cc6, - 0x266906, - 0x21afc7, - 0x2b6245, - 0x251907, - 0x344ec5, - 0x2b3a84, - 0x206686, - 0x2269c7, - 0x2ab54d, - 0x2a4087, - 0x3774c8, - 0x27bb49, - 0x223d86, - 0x36bd85, - 0x23ae44, - 0x34f386, - 0x21f406, - 0x234e86, - 0x29cc08, - 0x223283, - 0x210e03, - 0x343085, - 0x35c6c6, - 0x2b0345, - 0x2a5a48, - 0x2a07ca, - 0x246b04, - 0x359b48, - 0x296188, - 0x219347, - 0x331a49, - 0x2c0808, - 0x2829c7, - 0x2b5106, - 0x3c698a, - 0x34f408, - 0x307009, - 0x2af148, - 0x227f89, - 0x361107, - 0x303505, - 0x2ffd06, - 0x2b2948, - 0x24f988, - 0x313c48, - 0x31c5c8, - 0x244ac5, - 0x200d04, - 0x232588, - 0x23eb84, - 0x3c4d44, - 0x267c05, - 0x295647, - 0x2e6d09, - 0x210c07, - 0x21a5c5, - 0x278886, - 0x368186, - 0x213bc4, - 0x2a5386, - 0x27e044, - 0x292686, - 0x2e6ac6, - 0x214146, - 0x3bfc85, - 0x2a5907, - 0x20cc43, - 0x20a909, - 0x30fdc8, - 0x282844, - 0x28284d, - 0x29acc8, - 0x2f0148, - 0x306f86, - 0x283d09, - 0x2ceb09, - 0x2f7c85, - 0x2a08ca, - 0x26da4a, - 0x270c0c, - 0x270d86, - 0x2794c6, - 0x2caf86, - 0x39b709, - 0x21f986, - 0x222906, - 0x28ea86, - 0x34d748, - 0x31d6c6, - 0x2d4b8b, - 0x2957c5, - 0x21afc5, - 0x279cc5, - 0x340c06, - 0x215103, - 0x23b406, - 0x2a4007, - 0x2c4485, - 0x211e45, - 0x3b8505, - 0x33d006, - 0x2f7d44, - 0x334606, - 0x2a9789, - 0x340a8c, - 0x2b37c8, - 0x2a98c4, - 0x304e86, - 0x289f06, - 0x254648, - 0x225fc8, - 0x340989, - 0x344bc7, - 0x236589, - 0x271b06, - 0x2150c4, - 0x205fc4, - 0x281fc4, - 0x282f08, - 0x2e6b4a, - 0x35e2c6, - 0x36b487, - 0x382887, - 0x244a45, - 0x2f31c4, - 0x290c86, - 0x2b6286, - 0x20eec3, - 0x30fc07, - 0x3d35c8, - 0x2f7dca, - 0x345188, - 0x2dd348, - 0x33fac5, - 0x2a1405, - 0x2364c5, - 0x244e06, - 0x35cb06, - 0x2fe385, - 0x32dc09, - 0x2f2fcc, - 0x35b4c7, - 0x29b888, - 0x276705, - 0x602c84, - 0x229cc4, - 0x283484, - 0x218bc6, - 0x2a2d4e, - 0x32f2c7, - 0x21b1c5, - 0x2d524c, - 0x30af87, - 0x226947, - 0x22bb09, - 0x220d49, - 0x287fc5, - 0x30fdc8, - 0x308fc9, - 0x38ed05, - 0x2c43c8, - 0x2b9886, - 0x382146, - 0x23f204, - 0x28fe08, - 0x223f43, - 0x209284, - 0x2ab385, - 0x394e47, - 0x26bcc5, - 0x3bf149, - 0x2a5f8d, - 0x2c6506, - 0x3c37c4, - 0x226b08, - 0x20ae0a, - 0x21bf47, - 0x36ba05, - 0x2092c3, - 0x2a1f4e, - 0x24988c, - 0x305387, - 0x2a2f07, - 0x4230e9c7, - 0x14f0c6, - 0x46e44, - 0x210d83, - 0x21f9c5, - 0x283485, + 0x23a80b, + 0x2a3044, + 0x355f44, + 0x2d4444, + 0x2d8ec6, + 0x202804, + 0x222c48, + 0x359705, + 0x21c145, + 0x36b7c7, + 0x288109, + 0x334285, + 0x39110a, + 0x3db9c9, + 0x2b174a, + 0x3cfe49, + 0x3545c4, + 0x31dc05, + 0x2c75c8, + 0x3a34cb, + 0x2dea45, + 0x24c386, + 0x241304, + 0x27afc6, + 0x33bcc9, + 0x2e9ac7, + 0x346d88, + 0x2a94c6, + 0x26c2c7, + 0x281788, + 0x377746, + 0x3c72c4, + 0x3817c7, + 0x382e85, + 0x392987, + 0x267784, + 0x2c0b86, + 0x30ad48, + 0x29ea88, + 0x2ff987, + 0x202808, + 0x29c6c5, + 0x226004, + 0x38f3c8, + 0x202904, + 0x217345, + 0x30af44, + 0x2109c7, + 0x28bdc7, + 0x2823c8, + 0x2dcb06, + 0x27f885, + 0x27a888, + 0x246848, + 0x2a6c09, + 0x2261c6, + 0x22f648, + 0x281d0a, + 0x36f888, + 0x309745, + 0x21b986, + 0x2a7208, + 0x39ba0a, + 0x219507, + 0x285f85, + 0x292c08, + 0x270fc4, + 0x252446, + 0x2cbb48, + 0x3d0d46, + 0x334c08, + 0x2d7ac7, + 0x3c7506, + 0x2c2844, + 0x237687, + 0x2bc004, + 0x33bc87, + 0x367e0d, + 0x237cc5, + 0x2d6b0b, + 0x285606, + 0x251e88, + 0x2427c4, + 0x3c50c6, + 0x27d886, + 0x2d0bc7, + 0x29e10d, + 0x304807, + 0x2bc5c8, + 0x284145, + 0x270648, + 0x2d4a86, 0x29c748, - 0x299d49, - 0x3db306, - 0x2546c4, - 0x2f44c6, - 0x266e0b, - 0x2dc50c, - 0x24b8c7, - 0x2d4e45, - 0x3a76c8, - 0x2e4cc5, - 0x3c2507, - 0x3315c7, - 0x22ee45, - 0x215103, - 0x20fd44, - 0x3cb985, - 0x26e585, - 0x26e586, - 0x2a8f48, - 0x2269c7, - 0x3a4ac6, - 0x21cc86, - 0x34c406, - 0x2671c9, - 0x2111c7, - 0x27e146, - 0x2dc686, - 0x277146, - 0x2acb45, - 0x205746, - 0x383a05, - 0x28ba48, - 0x29528b, - 0x2909c6, - 0x3828c4, - 0x2d5b09, - 0x2a62c4, + 0x238606, + 0x3036c7, + 0x282749, + 0x35a587, + 0x28afc8, + 0x34a005, + 0x22a1c8, + 0x2aef85, + 0x228e05, + 0x362b45, + 0x24dec3, + 0x204584, + 0x292e05, + 0x3a2709, + 0x367906, + 0x2e9788, + 0x2c2105, + 0x2bde47, + 0x371bca, + 0x2d4109, + 0x2e524a, + 0x2dfd48, + 0x22820c, + 0x282f0d, + 0x311883, + 0x334b08, + 0x206245, + 0x2f2d46, + 0x384f06, + 0x31e585, + 0x3de109, + 0x33d2c5, + 0x27a888, + 0x258546, + 0x369706, + 0x2a8cc9, + 0x3a9007, + 0x293506, + 0x371b48, + 0x3bbb48, + 0x2ed607, + 0x2c974e, + 0x2d4cc5, + 0x23b3c5, + 0x3d0c48, + 0x271e87, + 0x200e42, + 0x2c9b84, + 0x36838a, + 0x3077c8, + 0x287b46, + 0x2a0588, + 0x2a5506, + 0x288b88, + 0x2b52c8, + 0x228dc4, + 0x2be205, + 0x668c84, + 0x668c84, + 0x668c84, + 0x20aec3, + 0x215a06, + 0x27ad46, + 0x2a458c, + 0x202dc3, + 0x267786, + 0x21a604, + 0x281488, + 0x28e885, + 0x368486, + 0x2c6d08, + 0x2e0e46, + 0x230646, + 0x3c5608, + 0x2da147, + 0x263f49, + 0x3ae60a, + 0x266644, + 0x29d485, + 0x2e4305, + 0x2d7746, + 0x361ac6, + 0x2a50c6, + 0x3dc246, + 0x264084, + 0x26408b, + 0x264a44, + 0x244285, + 0x2b3a45, + 0x288486, + 0x201b48, + 0x282dc7, + 0x32b044, + 0x25b603, + 0x270ac5, + 0x37b307, + 0x282ccb, + 0x23ee87, + 0x2c6c08, + 0x2be347, + 0x26b746, + 0x25d588, + 0x2c51cb, + 0x301506, + 0x212849, + 0x2c5345, + 0x31f203, + 0x2d41c6, + 0x2d79c8, + 0x20c2c3, + 0x24c343, + 0x281786, + 0x2a5506, + 0x3759ca, + 0x27cc45, + 0x27d6cb, + 0x2a534b, + 0x213c03, + 0x20ea43, + 0x2ba1c4, + 0x370587, + 0x277d04, + 0x281484, + 0x2bb8c4, + 0x36fb88, + 0x2ccf88, + 0x214d49, + 0x2d7588, + 0x3b2d07, + 0x245806, + 0x2e93cf, + 0x2d4e06, + 0x2df404, + 0x2ccdca, + 0x37b207, + 0x2bc106, + 0x292a49, + 0x214cc5, + 0x23f0c5, + 0x214e06, + 0x22a303, + 0x271009, + 0x21db06, + 0x34c2c9, + 0x391686, + 0x26a705, + 0x35c905, + 0x204583, + 0x3706c8, + 0x32b787, + 0x3de2c4, + 0x281308, + 0x371dc4, + 0x359006, + 0x2bf706, + 0x23d646, + 0x2d9e09, + 0x300805, + 0x29ee06, + 0x2713c9, + 0x2d3e06, + 0x2e94c6, + 0x3a14c6, + 0x22bd85, + 0x30af46, + 0x3036c4, + 0x33a345, + 0x217484, + 0x2bcf46, + 0x298ac4, + 0x2109c3, + 0x285c05, + 0x233d88, + 0x3572c7, + 0x306f49, + 0x285e88, + 0x29f751, + 0x2c1f0a, + 0x2fcf07, + 0x357e46, + 0x21a604, + 0x2ca648, + 0x2ea008, + 0x29f90a, + 0x2cefcd, + 0x2a6dc6, + 0x3c5706, + 0x237746, + 0x21c147, + 0x2bc685, + 0x286c47, + 0x2813c5, + 0x2baf04, + 0x3c5e46, + 0x224dc7, + 0x270d0d, + 0x2a7147, + 0x37ef48, + 0x27ab89, + 0x21b886, + 0x35bb05, + 0x23c2c4, + 0x2af546, + 0x20c106, + 0x307946, + 0x2a0e08, + 0x21ad83, + 0x2465c3, + 0x349b05, + 0x31ec06, + 0x2b5285, + 0x2a96c8, + 0x2a3d8a, + 0x347344, + 0x281488, + 0x299408, + 0x2882c7, + 0x286589, + 0x2c6908, + 0x280747, + 0x2bbb46, + 0x3d0d4a, + 0x2af5c8, + 0x30c989, + 0x2b23c8, + 0x21ef89, + 0x357d07, + 0x312785, + 0x2a5906, 0x2b9808, - 0x31c087, - 0x285304, - 0x2bff48, - 0x2c59c4, - 0x2acb84, - 0x398305, - 0x31c4c6, - 0x3da487, - 0x24e4c3, - 0x2a17c5, - 0x2fb684, - 0x3c0b06, - 0x2f7d08, - 0x3db085, - 0x294f49, - 0x313985, - 0x3736c8, - 0x21a887, - 0x32df08, - 0x2bfb87, - 0x2f2909, - 0x282b06, - 0x341c06, - 0x28ea84, - 0x3abf45, - 0x30d1cc, - 0x279cc7, - 0x27a747, - 0x231548, - 0x2c6506, - 0x2a3f44, - 0x34ab44, - 0x388fc9, - 0x2cb086, - 0x26df07, - 0x210a44, - 0x261606, - 0x3a4405, - 0x2d2807, - 0x2d4b06, - 0x2645c9, - 0x2cfa47, - 0x297a87, - 0x2a4ec6, - 0x261545, - 0x281448, - 0x222508, - 0x22fa46, - 0x3db0c5, - 0x2c7406, - 0x2017c3, - 0x29c5c9, - 0x2a188e, - 0x2bf2c8, - 0x3174c8, - 0x22f84b, - 0x295186, - 0x379b04, - 0x238e44, - 0x2a198a, - 0x213147, - 0x27e205, - 0x213a89, - 0x2c31c5, - 0x3c4d87, - 0x230504, - 0x299187, - 0x214fc8, - 0x2cc646, - 0x2b9d09, - 0x2c090a, - 0x2130c6, - 0x29a806, - 0x2af505, - 0x396405, - 0x34bac7, - 0x242788, - 0x3a4348, - 0x26b006, - 0x28c885, - 0x23168e, - 0x226384, - 0x22f9c5, - 0x278209, - 0x2d7688, - 0x28d406, - 0x29e7cc, - 0x2a03d0, - 0x2a298f, - 0x2a44c8, - 0x313987, - 0x3bfc85, - 0x294105, - 0x3da309, - 0x294109, - 0x278f46, - 0x2d5107, - 0x3abe45, - 0x306a89, - 0x353186, - 0x21f7cd, - 0x281e89, - 0x219344, - 0x2bf048, - 0x232649, + 0x252008, + 0x224508, + 0x222dc8, + 0x244285, + 0x200d04, + 0x232708, + 0x241084, + 0x3cfc44, + 0x26a705, + 0x2949c7, + 0x287ec9, + 0x2d09c7, + 0x20f8c5, + 0x277b06, + 0x36f1c6, + 0x201c44, + 0x2a9006, + 0x27db04, + 0x291746, + 0x287c86, + 0x212e86, + 0x3c8785, + 0x2a9587, + 0x203d03, + 0x211609, + 0x330d08, + 0x2805c4, + 0x2805cd, + 0x29eb88, + 0x32a608, + 0x30c906, + 0x282849, + 0x2d4109, + 0x33b9c5, + 0x2a3e8a, + 0x291aca, + 0x2b444c, + 0x2b45c6, + 0x278406, + 0x2d5686, + 0x38ce89, + 0x2f2f86, + 0x21dd86, + 0x33d386, + 0x307588, + 0x202806, + 0x2de54b, + 0x294b45, + 0x21c145, + 0x279485, + 0x203e06, + 0x226043, + 0x23d5c6, + 0x2a70c7, + 0x2ca505, + 0x2d1c05, + 0x3b1385, + 0x310686, + 0x32fa44, + 0x32fa46, + 0x2ab289, + 0x203c8c, + 0x2bac48, + 0x22b284, + 0x30ac46, + 0x285706, + 0x2d79c8, + 0x2bbc48, + 0x203b89, + 0x343d47, + 0x356589, + 0x2726c6, + 0x22c144, + 0x2082c4, + 0x27f6c4, + 0x281788, + 0x287d0a, + 0x334206, + 0x3677c7, + 0x392c07, + 0x244205, + 0x36c944, + 0x28fe06, + 0x2bc6c6, + 0x21d2c3, + 0x330b47, + 0x20d088, + 0x33bb0a, + 0x22be48, + 0x20ad88, + 0x298b05, + 0x2a49c5, + 0x3564c5, + 0x2445c6, + 0x247486, + 0x33c885, + 0x32aec9, + 0x36c74c, + 0x2f4ec7, + 0x29f988, + 0x2521c5, + 0x668c84, + 0x265444, + 0x2d6e44, + 0x218706, + 0x2a650e, + 0x23f147, + 0x21c345, + 0x2dec0c, + 0x310b07, + 0x224d47, + 0x226fc9, + 0x219e49, + 0x285f85, + 0x330d08, + 0x2bd9c9, + 0x38ffc5, + 0x2ca448, + 0x2c0886, + 0x38f646, + 0x202c44, + 0x28ee48, + 0x21ba43, + 0x215604, + 0x270b45, + 0x396f07, + 0x2c2605, + 0x281bc9, + 0x2a118d, + 0x2b3046, + 0x3df784, + 0x3b9d08, + 0x20e7ca, + 0x21c847, + 0x367d45, + 0x215643, + 0x2a550e, + 0x3707cc, + 0x30b147, + 0x2a66c7, + 0x443960c7, + 0xaf286, + 0x647c4, + 0x203083, + 0x2f2fc5, + 0x2d6e45, + 0x2a0948, + 0x29dc09, + 0x22b186, + 0x277d04, + 0x2fce46, + 0x331bcb, + 0x2e844c, + 0x24df87, + 0x2de805, + 0x3a9f48, + 0x2ed3c5, + 0x2ccdc7, + 0x2f4cc7, + 0x245fc5, + 0x226043, + 0x20c584, + 0x2e4205, + 0x269e05, + 0x269e06, + 0x2a9dc8, + 0x224dc7, + 0x385206, + 0x33a686, + 0x362a86, + 0x225249, + 0x2d0f87, + 0x250f86, + 0x2e85c6, + 0x276d06, + 0x2b0ac5, + 0x20a586, + 0x39b0c5, + 0x28d808, + 0x29428b, + 0x28fb46, + 0x392c44, + 0x304e49, + 0x2a9fc4, + 0x2c0808, + 0x30e907, + 0x283ec4, + 0x2c5dc8, + 0x2cb5c4, + 0x2b0b04, + 0x274785, + 0x318886, + 0x36fac7, + 0x23db43, + 0x2a4d85, + 0x2fd1c4, + 0x23b406, + 0x33ba48, + 0x202705, + 0x293f49, + 0x350105, + 0x267788, + 0x21a4c7, + 0x32b1c8, + 0x2c5a07, + 0x241889, + 0x280886, + 0x33e906, + 0x2a78c4, + 0x355e85, + 0x31320c, + 0x279487, + 0x279c87, + 0x361708, + 0x2b3046, + 0x2a7004, + 0x34b0c4, + 0x389409, + 0x2d5786, + 0x270507, + 0x2d0804, + 0x326b06, + 0x38a805, + 0x2dc647, + 0x2de4c6, + 0x251249, + 0x2f0387, + 0x29bc87, + 0x2a8b46, + 0x326a45, + 0x27f408, + 0x21d988, + 0x245a06, + 0x202745, + 0x2cca86, + 0x20af03, + 0x2a07c9, + 0x2a4e4e, + 0x2c5748, + 0x371ec8, + 0x24580b, + 0x294186, + 0x385544, + 0x230644, + 0x2a4f4a, + 0x211987, + 0x251045, + 0x212849, + 0x2c9685, + 0x3cfc87, + 0x2305c4, + 0x3c7b07, + 0x318988, + 0x2d4906, + 0x2c0d09, + 0x2c6a0a, + 0x211906, + 0x29e6c6, + 0x2b39c5, + 0x398545, + 0x36ac07, + 0x245608, + 0x38a748, + 0x228dc6, + 0x35c985, + 0x36184e, + 0x2c70c4, + 0x245985, + 0x277489, + 0x2eab08, + 0x28e286, + 0x2a2acc, + 0x2a3990, + 0x2a614f, + 0x2a8148, + 0x350107, + 0x3c8785, + 0x292e05, + 0x36f949, + 0x292e09, + 0x2cfe06, + 0x2deac7, + 0x355d85, + 0x237c49, 0x35e486, - 0x3899c5, - 0x341c06, - 0x275c89, - 0x27b108, - 0x209a85, - 0x28fe04, - 0x29e98b, - 0x35e345, - 0x245b86, - 0x284706, - 0x252a06, - 0x2a388b, - 0x295049, - 0x21cbc5, - 0x391d47, - 0x331706, - 0x212dc6, - 0x283208, - 0x2b5209, - 0x37728c, - 0x31bc48, - 0x317f06, - 0x338fc3, - 0x22d046, - 0x2a36c5, - 0x27fb48, - 0x28c286, - 0x2d2a48, - 0x242b85, - 0x292745, - 0x21a9c8, - 0x3a9dc7, - 0x3a4707, - 0x2f5247, - 0x319dc8, - 0x313ac8, - 0x2b5b46, - 0x2b6947, - 0x306387, - 0x2a358a, - 0x206383, - 0x340c06, - 0x231605, - 0x288bc4, - 0x27bb49, - 0x2f2884, - 0x202244, - 0x2a0c44, - 0x2a2f0b, - 0x32e407, - 0x2318c5, - 0x2981c8, - 0x278886, - 0x278888, - 0x27e7c6, - 0x28fd45, - 0x290005, - 0x2915c6, - 0x2937c8, - 0x293c88, - 0x27bd06, - 0x29800f, - 0x29c090, - 0x3c12c5, - 0x20cc43, - 0x22aa85, - 0x31ad88, - 0x294009, - 0x38ee48, - 0x2d4f08, - 0x31f888, - 0x32e4c7, - 0x278549, - 0x2d2c48, - 0x285a84, - 0x2a0ac8, - 0x2e9dc9, - 0x2b7607, - 0x2b0104, - 0x210cc8, - 0x2a56ca, - 0x2fb906, - 0x215146, - 0x34fb09, - 0x2a0607, - 0x2d0308, - 0x230588, - 0x21d348, - 0x37f785, - 0x207685, - 0x21afc5, - 0x283445, - 0x2b4a07, - 0x244bc5, - 0x2c4485, - 0x3cfec6, - 0x38ed87, - 0x2d0e07, - 0x2a59c6, + 0x2f2dcd, + 0x27f589, + 0x281484, + 0x2c54c8, + 0x2327c9, + 0x3343c6, + 0x278a05, + 0x33e906, + 0x346c49, + 0x2d0688, + 0x206a05, + 0x281e04, + 0x2a2c8b, + 0x334285, + 0x246586, + 0x283246, + 0x3b4246, + 0x2875cb, + 0x294049, + 0x33a5c5, + 0x393807, + 0x2c1e86, + 0x231f46, + 0x281a88, + 0x224f09, + 0x37ed0c, + 0x37b108, + 0x31aac6, + 0x32dc83, + 0x22f306, + 0x241745, + 0x27e208, + 0x3d9d46, + 0x2dc888, + 0x380445, + 0x291805, + 0x21a608, + 0x3bba07, + 0x384e47, + 0x34c747, + 0x302a48, + 0x2d7848, + 0x2e9f06, + 0x2bcd87, + 0x21f707, + 0x2b3f4a, + 0x2168c3, + 0x203e06, + 0x22b3c5, + 0x213504, + 0x27ab89, + 0x241804, + 0x204844, + 0x2a4204, + 0x2a66cb, + 0x32b6c7, + 0x310645, + 0x29c3c8, + 0x277b06, + 0x277b08, + 0x27cb86, + 0x28ed85, + 0x28f045, + 0x290746, + 0x292408, + 0x292988, + 0x27ad46, + 0x29c20f, + 0x2a0290, + 0x3d0845, + 0x203d03, + 0x22c205, + 0x31bd08, + 0x292d09, + 0x390108, + 0x2de8c8, + 0x235288, + 0x32b787, + 0x2777c9, + 0x2dca88, + 0x291004, + 0x2a4088, + 0x35ab89, + 0x2bd387, + 0x34de44, + 0x2d0a88, + 0x2a934a, + 0x2fd446, + 0x2a6dc6, + 0x226089, + 0x2a3bc7, + 0x2d9c88, + 0x21fd08, + 0x33ad48, + 0x24ef85, + 0x3d3205, + 0x21c145, 0x2d6e05, - 0x245b86, - 0x20ee45, - 0x2bca88, - 0x3abdc4, - 0x2c96c6, - 0x324c84, - 0x2bfd48, - 0x2c97ca, - 0x27c48c, - 0x336285, - 0x21b086, - 0x377446, - 0x28e886, - 0x317f84, - 0x3a4d85, - 0x27dd87, - 0x2a0689, - 0x2cef47, - 0x602c84, - 0x602c84, - 0x32e285, - 0x217684, - 0x29dd4a, - 0x278706, - 0x308dc4, - 0x3b06c5, - 0x2b41c5, - 0x2b6184, - 0x284347, - 0x336c87, - 0x2ce988, - 0x2c7508, - 0x209a89, - 0x295e08, - 0x29df0b, - 0x26f484, - 0x2921c5, - 0x389385, - 0x2f51c9, - 0x2b5209, - 0x2d5a08, - 0x228d48, - 0x219504, - 0x289f45, - 0x218e03, - 0x359885, - 0x29afc6, - 0x299b8c, - 0x210946, - 0x3898c6, - 0x28d685, - 0x33d088, - 0x3d83c6, - 0x254a06, - 0x215146, - 0x26368c, - 0x389444, - 0x34c54a, - 0x28d5c8, - 0x2999c7, - 0x2fb586, - 0x3db3c7, - 0x2f40c5, - 0x36b6c6, - 0x366906, - 0x376047, - 0x2c0604, - 0x20ea85, - 0x278204, - 0x2b3b07, - 0x278448, - 0x27934a, - 0x2820c7, - 0x2ac747, - 0x313907, - 0x2e4e09, - 0x299b8a, - 0x229a03, - 0x3d2c85, - 0x214183, - 0x2b4ec9, - 0x361248, - 0x295bc7, - 0x38ef49, - 0x222606, - 0x3b5e08, - 0x393885, - 0x248f8a, - 0x3b0a49, - 0x2492c9, - 0x3d8287, - 0x2b5d49, - 0x214048, - 0x36a2c6, - 0x21b248, - 0x212187, - 0x26eb07, - 0x2a4287, - 0x2d1c48, - 0x3cd4c6, - 0x2a5485, - 0x27dd87, - 0x29a308, - 0x34c384, - 0x2fd284, - 0x294707, - 0x2b0707, - 0x308e4a, - 0x36a246, - 0x32f70a, - 0x2c3607, - 0x226147, - 0x20eb44, - 0x29d044, - 0x2d2706, - 0x36c404, - 0x36c40c, - 0x308d05, - 0x214e09, - 0x2b3644, - 0x2b6245, - 0x20ad88, - 0x293d45, - 0x38fe46, - 0x294244, - 0x2ad88a, - 0x2b3e46, - 0x293a0a, - 0x3c5107, - 0x2d0145, - 0x229fc5, - 0x244a8a, - 0x293945, - 0x2a3c06, - 0x23eb84, - 0x2b33c6, - 0x34bb85, - 0x28c346, - 0x2f188c, - 0x26390a, - 0x26db44, - 0x22f846, - 0x2a0607, - 0x2d4a84, - 0x34d748, - 0x2e7f46, - 0x382709, - 0x2c20c9, - 0x348289, - 0x2cf246, - 0x212286, - 0x21b387, - 0x32db48, - 0x212089, - 0x32e407, - 0x298346, - 0x280047, - 0x2667c5, - 0x226384, - 0x21af47, - 0x306545, - 0x288b05, + 0x2bb447, + 0x226045, + 0x2ca505, + 0x3dde06, + 0x390047, + 0x3a3407, + 0x2a9646, + 0x2e0285, + 0x246586, + 0x241985, + 0x2c4d88, + 0x355d04, + 0x2d3e86, + 0x324604, + 0x2c5bc8, + 0x318c0a, + 0x27b4cc, + 0x23aa05, + 0x21c206, + 0x37eec6, + 0x202586, + 0x31ab44, + 0x3b9a05, + 0x27c447, + 0x2a3c49, + 0x2d9307, + 0x668c84, + 0x668c84, + 0x32b545, + 0x2dda04, + 0x2a204a, + 0x277986, + 0x2bd7c4, + 0x3c2d85, + 0x3bd405, + 0x2bc5c4, + 0x282e87, + 0x3c3a87, + 0x2d8ec8, + 0x26d5c8, + 0x206a09, + 0x372488, + 0x2a220b, + 0x2acc44, + 0x232045, + 0x3897c5, + 0x34c6c9, + 0x224f09, + 0x304d48, + 0x34cc48, + 0x288484, + 0x285745, + 0x2041c3, + 0x2d7705, + 0x29ee86, + 0x29da4c, + 0x20c006, + 0x278906, + 0x28e505, + 0x310708, + 0x2e86c6, + 0x357fc6, + 0x2a6dc6, + 0x22bbcc, + 0x389884, + 0x362bca, + 0x28e448, + 0x29d887, + 0x2fd0c6, + 0x22b247, + 0x2fca45, + 0x367a06, + 0x35ee86, + 0x372987, + 0x2c6704, + 0x210ac5, + 0x277484, + 0x2baf87, + 0x2776c8, + 0x27828a, + 0x280b87, + 0x2aa847, + 0x350087, + 0x2ed509, + 0x29da4a, + 0x22c103, + 0x357285, + 0x212ec3, + 0x2bb909, + 0x2d7c08, + 0x372247, + 0x390209, + 0x21da86, + 0x339f88, + 0x395385, + 0x24694a, + 0x343809, + 0x370209, + 0x3db607, + 0x2ea109, + 0x212d88, + 0x288d86, + 0x21c3c8, + 0x2d1f47, + 0x264187, + 0x3db9c7, + 0x2daf48, + 0x30aac6, + 0x2a9105, + 0x27c447, + 0x29e1c8, + 0x362a04, + 0x306044, + 0x293407, + 0x2b5647, + 0x2bd84a, + 0x288d06, + 0x32eeca, + 0x2c9ac7, + 0x2c6e87, + 0x210b84, + 0x29d444, + 0x2dc546, + 0x35c184, + 0x35c18c, + 0x30e845, + 0x2172c9, + 0x2ef004, + 0x2bc685, + 0x20e748, + 0x292a45, + 0x391106, + 0x292f44, + 0x2acb4a, + 0x2ef646, + 0x255fca, + 0x3d0007, + 0x215f85, + 0x22a305, + 0x24424a, + 0x292585, + 0x2a6cc6, + 0x241084, + 0x2ba346, + 0x36acc5, + 0x3d9e06, + 0x2ff98c, + 0x2e18ca, + 0x291bc4, + 0x245806, + 0x2a3bc7, + 0x2de444, + 0x307588, + 0x24c286, + 0x392a89, + 0x2c8349, + 0x341189, + 0x2d9606, + 0x2d2046, + 0x21c507, + 0x32ae08, + 0x2d1e49, + 0x32b6c7, + 0x29c546, + 0x26c347, + 0x237605, + 0x2c70c4, + 0x21c0c7, + 0x21f8c5, + 0x28a2c5, 0x200cc7, - 0x22ed08, - 0x3a7646, - 0x29b14d, - 0x29c94f, - 0x2a1d8d, - 0x205484, - 0x233d06, - 0x2d9448, - 0x28ea45, - 0x2a3748, - 0x261e8a, - 0x219344, - 0x2b53c6, - 0x2d60c7, - 0x219cc7, - 0x2d8dc9, - 0x21b205, - 0x2b6184, - 0x2b864a, - 0x2c03c9, - 0x2b5e47, - 0x2f2dc6, - 0x35e486, - 0x289e86, - 0x380606, - 0x2d868f, - 0x2d9309, - 0x31d6c6, - 0x388c06, - 0x32d209, - 0x2b6a47, - 0x214703, - 0x243846, - 0x208a43, - 0x35bf08, - 0x27fe87, - 0x2a46c9, - 0x31ca88, - 0x3a4848, - 0x2ff3c6, - 0x210889, - 0x35b405, - 0x22cf84, - 0x3035c7, - 0x39b785, - 0x205484, - 0x231988, - 0x20f104, - 0x2b6787, - 0x36d146, - 0x269e45, - 0x2af148, - 0x35e34b, - 0x3102c7, - 0x244d06, - 0x2ca784, - 0x379a86, - 0x267c05, - 0x306545, - 0x2811c9, - 0x283f49, - 0x26eb44, - 0x26eb85, - 0x22f885, - 0x248e06, - 0x30fec8, - 0x2c29c6, - 0x3d340b, - 0x384fca, - 0x2bfc85, - 0x290086, - 0x246805, - 0x2db7c5, - 0x296307, - 0x340e88, - 0x236584, - 0x261a86, - 0x293d06, - 0x214207, - 0x31da04, - 0x27ee06, - 0x21f245, - 0x21f249, - 0x212484, - 0x2f3349, - 0x27bd06, - 0x2c51c8, - 0x22f885, - 0x382985, - 0x28c346, - 0x377189, - 0x220d49, - 0x389946, - 0x2d7788, - 0x2a60c8, - 0x2467c4, - 0x2b8ac4, - 0x2b8ac8, - 0x2e6288, - 0x236689, - 0x29af46, - 0x215146, - 0x33860d, - 0x31f2c6, - 0x3215c9, - 0x202945, - 0x208a86, - 0x27b288, - 0x334545, - 0x3063c4, - 0x267c05, - 0x283a88, - 0x29db09, - 0x2782c4, - 0x2b9b86, - 0x3071ca, - 0x305288, - 0x308fc9, - 0x268a0a, - 0x38eec6, - 0x29cb08, - 0x3c22c5, - 0x28d848, - 0x2f4145, - 0x2224c9, - 0x33a989, - 0x20fe02, - 0x292b85, - 0x271786, - 0x27bc47, - 0x322b85, - 0x2fb486, - 0x312c48, - 0x2c6506, - 0x2c1209, - 0x27a846, - 0x283088, - 0x389d05, - 0x3ddc06, - 0x2f74c8, - 0x282f08, - 0x361008, - 0x315708, - 0x205744, - 0x21f543, - 0x2c1444, - 0x2822c6, - 0x266804, - 0x317407, - 0x254909, - 0x2c9a45, - 0x230586, - 0x243846, - 0x2a8d8b, - 0x2b56c6, - 0x33fd06, - 0x2ccd48, - 0x229a46, - 0x2bd1c3, - 0x203e83, - 0x226384, - 0x22f1c5, - 0x2b7ac7, - 0x278448, - 0x27844f, - 0x27dc8b, - 0x30fcc8, - 0x2b9c06, - 0x30ffce, - 0x244ec3, - 0x2b7a44, - 0x2b5645, - 0x2b6006, - 0x290d8b, - 0x295706, - 0x227789, - 0x269e45, - 0x24e408, - 0x204d88, - 0x220c0c, - 0x2a2f46, - 0x3598c6, - 0x2dedc5, - 0x288ec8, - 0x27c485, - 0x351c88, - 0x29eb4a, - 0x2a21c9, - 0x602c84, + 0x245e88, + 0x3a9ec6, + 0x29f00d, + 0x2a0b4f, + 0x2a534d, + 0x202d84, + 0x233e86, + 0x2e1c88, + 0x33d345, + 0x2b4108, + 0x252f0a, + 0x281484, + 0x331e06, + 0x2abe07, + 0x2b7d47, + 0x2da209, + 0x21c385, + 0x2bc5c4, + 0x2be14a, + 0x2c64c9, + 0x2ea207, + 0x30b706, + 0x3343c6, + 0x285686, + 0x381886, + 0x2e158f, + 0x2e1b49, + 0x202806, + 0x389046, + 0x297e89, + 0x2bce87, + 0x2146c3, + 0x22bd46, + 0x212503, + 0x31e448, + 0x26c187, + 0x2a8349, + 0x2bf588, + 0x384f88, + 0x33c506, + 0x20bf49, + 0x2f4e05, + 0x22f244, + 0x312847, + 0x38cf05, + 0x202d84, + 0x361b48, + 0x211c44, + 0x2bcbc7, + 0x36c106, + 0x263645, + 0x2b23c8, + 0x33428b, + 0x331207, + 0x2444c6, + 0x2d4e84, + 0x3854c6, + 0x26a705, + 0x21f8c5, + 0x27f189, + 0x282a89, + 0x2641c4, + 0x264205, + 0x245845, + 0x2467c6, + 0x330e08, + 0x2c8e86, + 0x20cecb, + 0x3bc9ca, + 0x2c5b05, + 0x28f0c6, + 0x23eb85, + 0x24a285, + 0x292647, + 0x204088, + 0x292484, + 0x37fb46, + 0x292a06, + 0x212f47, + 0x31f1c4, + 0x27d886, + 0x3c2245, + 0x3c2249, + 0x2d2244, + 0x36cac9, + 0x27ad46, + 0x2cac48, + 0x245845, + 0x392d05, + 0x3d9e06, + 0x37ec09, + 0x219e49, + 0x278986, + 0x2eac08, + 0x2a12c8, + 0x23eb44, + 0x2be9c4, + 0x2be9c8, + 0x3b2b88, + 0x356689, + 0x29ee06, + 0x2a6dc6, + 0x33384d, + 0x3ae006, + 0x3218c9, + 0x268945, + 0x214e06, + 0x33aec8, + 0x32f985, + 0x21f744, + 0x26a705, + 0x2825c8, + 0x2a1e09, + 0x277544, + 0x2c0b86, + 0x30cb4a, + 0x30b048, + 0x2bd9c9, + 0x26ad4a, + 0x390186, + 0x2a0d08, + 0x2ccb85, + 0x2f0988, + 0x2fcac5, + 0x21d949, + 0x336449, + 0x20c642, + 0x2c5345, + 0x272346, + 0x27ac87, + 0x213505, + 0x3469c6, + 0x316908, + 0x2b3046, + 0x2c7489, + 0x279d86, + 0x281908, + 0x278d45, + 0x38e4c6, + 0x3037c8, + 0x281788, + 0x357c08, + 0x318488, + 0x20a584, + 0x20c243, + 0x2c76c4, + 0x280d86, + 0x237644, + 0x371e07, + 0x357ec9, + 0x2d4445, + 0x21fd06, + 0x22bd46, + 0x2a9c0b, + 0x2bc046, + 0x298d46, + 0x2d3f88, + 0x264a46, + 0x215d83, + 0x208503, + 0x2c70c4, + 0x22f545, + 0x244847, + 0x2776c8, + 0x2776cf, + 0x27c34b, + 0x330c08, + 0x2c0c06, + 0x330f0e, + 0x23b443, + 0x2447c4, + 0x2bbfc5, + 0x2bc446, + 0x28ff0b, + 0x294a86, + 0x221089, + 0x263645, + 0x23da88, + 0x3d29c8, + 0x219d0c, + 0x2a6706, + 0x2d7746, + 0x2e2d45, + 0x28ad88, + 0x27b4c5, + 0x34f108, + 0x2a2e4a, + 0x2a5789, + 0x668c84, 0x2000c2, - 0x4820c302, + 0x4a201242, 0x200382, - 0x224e44, - 0x206a42, - 0x303f84, - 0x205642, - 0xca43, + 0x221dc4, + 0x209e82, + 0x306c44, + 0x208482, + 0x3dc3, 0x2003c2, - 0x209482, - 0x9fe08, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x211543, - 0x20a803, - 0x216603, - 0x248343, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x224e44, - 0x20a803, - 0x216603, - 0x234c83, - 0x242244, - 0x22c0c3, - 0x235604, - 0x232c43, - 0x2db1c4, - 0x228b03, - 0x322e47, - 0x211543, - 0x20ca43, - 0x31b008, - 0x216603, - 0x280acb, - 0x2f55c3, - 0x240986, - 0x219f82, - 0x2eec0b, - 0x232c43, - 0x228b03, - 0x20a803, - 0x216603, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x216603, - 0x221003, - 0x204383, + 0x2090c2, + 0x9a048, + 0x29904, + 0x214a83, + 0x232dc3, + 0x308003, + 0xccc2, + 0x49582, + 0x23c803, + 0x21a3c3, + 0x242543, + 0xc782, + 0xc2c2, + 0x1b82, + 0x202703, + 0x214a83, + 0x232dc3, + 0x308003, + 0x221dc4, + 0x21a3c3, + 0x242543, + 0x241f83, + 0x2d3684, + 0x214a83, + 0x235b44, + 0x232dc3, + 0x2e3504, + 0x308003, + 0x2137c7, + 0x23c803, + 0x203dc3, + 0x31bf88, + 0x242543, + 0x27cfcb, + 0x2fdbc3, + 0x2431c6, + 0x233442, + 0x2f850b, + 0x232dc3, + 0x308003, + 0x21a3c3, + 0x242543, + 0x214a83, + 0x232dc3, + 0x308003, + 0x242543, + 0x21a103, + 0x208a03, 0x2000c2, - 0x9fe08, - 0x397705, - 0x3065c8, - 0x2e2bc8, - 0x20c302, - 0x329085, - 0x3bfd47, - 0x201bc2, - 0x2401c7, + 0x9a048, + 0x399c45, + 0x21f948, + 0x2e3648, + 0x201242, + 0x343045, + 0x3c8847, + 0x203c42, + 0x242a07, 0x200382, - 0x254f47, - 0x2bd949, - 0x26c708, - 0x21d1c9, - 0x208582, - 0x3b04c7, - 0x3880c4, - 0x3bfe07, - 0x384ec7, - 0x259902, - 0x211543, - 0x205a02, - 0x205642, + 0x2555c7, + 0x3742c9, + 0x26d188, + 0x33abc9, + 0x20b342, + 0x3c7387, + 0x22dd84, + 0x3c8907, + 0x3bc8c7, + 0x25ac42, + 0x23c803, + 0x202382, + 0x208482, 0x2003c2, - 0x2161c2, + 0x214282, 0x200902, - 0x209482, - 0x2d6405, - 0x21bb85, - 0xc302, - 0x32c43, - 0x22c0c3, - 0x232c43, - 0x210b03, - 0x228b03, - 0x204f43, - 0x20a803, - 0x216603, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x20a803, - 0x216603, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x211543, - 0x20a803, - 0x6d9c3, - 0x216603, - 0x8083, + 0x2090c2, + 0x2df885, + 0x210205, + 0x1242, + 0x32dc3, + 0x214a83, + 0x232dc3, + 0x29a643, + 0x308003, + 0x206c03, + 0x21a3c3, + 0x242543, + 0x214a83, + 0x232dc3, + 0x308003, + 0x21a3c3, + 0x242543, + 0x214a83, + 0x232dc3, + 0x308003, + 0x23c803, + 0x21a3c3, + 0x1b4103, + 0x242543, + 0xa983, 0x101, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x224e44, - 0x214543, - 0x20a803, - 0x6d9c3, - 0x216603, - 0x216e03, - 0x4b50bb86, - 0xe85c3, - 0xca9c5, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x20a803, - 0x216603, - 0x20c302, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x20a803, - 0x6d9c3, - 0x216603, - 0x82c2, - 0x9fe08, - 0x12cdc3, - 0xca43, - 0x6d9c3, - 0x42744, - 0x142a744, - 0xe50c5, + 0x214a83, + 0x232dc3, + 0x308003, + 0x221dc4, + 0x21bc83, + 0x21a3c3, + 0x1b4103, + 0x242543, + 0x214903, + 0x4d4ae8c6, + 0x239c3, + 0xd50c5, + 0x214a83, + 0x232dc3, + 0x308003, + 0x21a3c3, + 0x242543, + 0x201242, + 0x214a83, + 0x232dc3, + 0x308003, + 0x21a3c3, + 0x1b4103, + 0x242543, + 0x1b02, + 0x9a048, + 0x12a4c3, + 0x3dc3, + 0x1b4103, + 0x455c4, + 0x14226c4, + 0xed7c5, 0x2000c2, - 0x392104, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x241f43, - 0x22cd85, - 0x214543, - 0x20e403, - 0x20a803, - 0x24bbc3, - 0x216603, - 0x20c603, - 0x2422c3, - 0x205b03, + 0x393bc4, + 0x214a83, + 0x232dc3, + 0x308003, + 0x231a43, + 0x22d805, + 0x21bc83, + 0x21a8c3, + 0x21a3c3, + 0x24e283, + 0x242543, + 0x20e2c3, + 0x266603, + 0x207783, 0x5c2, - 0x2d7c2, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x20a803, - 0x216603, + 0x2aec2, + 0x214a83, + 0x232dc3, + 0x308003, + 0x21a3c3, + 0x242543, 0x2000c2, - 0x248343, - 0x20c302, - 0x232c43, - 0x228b03, - 0x224e44, - 0x20a803, - 0x216603, - 0x209482, - 0x9fe08, - 0x228b03, - 0x6d9c3, - 0x9fe08, - 0x6d9c3, - 0x26fb43, - 0x22c0c3, - 0x22fd84, - 0x232c43, - 0x228b03, - 0x203dc2, - 0x211543, - 0x20a803, - 0x216603, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x203dc2, - 0x238cc3, - 0x20a803, - 0x216603, - 0x2ed343, - 0x20c603, + 0x202703, + 0x201242, + 0x2a42, + 0x232dc3, + 0x308003, + 0x221dc4, + 0x21a3c3, + 0x242543, + 0x2090c2, + 0x9a048, + 0x308003, + 0x1b4103, + 0x9a048, + 0x1b4103, + 0x26f6c3, + 0x214a83, + 0x22fe44, + 0x232dc3, + 0x308003, + 0x206182, + 0x23c803, + 0x21a3c3, + 0x3dc3, + 0x242543, + 0x214a83, + 0x232dc3, + 0x308003, + 0x206182, + 0x2137c3, + 0x21a3c3, + 0x242543, + 0x2f7103, + 0x20e2c3, 0x2000c2, - 0x20c302, - 0x228b03, - 0x20a803, - 0x216603, - 0x240985, - 0x127206, - 0x242244, - 0x219f82, - 0x9fe08, + 0x201242, + 0x308003, + 0x21a3c3, + 0x242543, + 0x2431c5, + 0x14fc86, + 0x2d3684, + 0x233442, + 0x882, + 0x9a048, + 0x2a42, + 0x49582, + 0x2982, 0x2000c2, - 0x12eb85, - 0x1c508, - 0x175583, - 0x20c302, - 0x4fd40486, - 0xd944, - 0x10a7cb, - 0x34786, - 0x11647, - 0x1b8dc9, - 0x232c43, - 0x47508, - 0x4750b, - 0x4798b, - 0x480cb, - 0x4840b, + 0x139b05, + 0x1ce08, + 0x991c3, + 0x201242, + 0x3c604, + 0x51c6c486, + 0x8d04, + 0x10fe4b, + 0x34ac6, + 0xd1407, + 0x12eb09, + 0x232dc3, + 0x48248, + 0x4824b, 0x486cb, - 0x48b0b, - 0x7386, - 0x228b03, - 0x20005, - 0x2a44, - 0x20e943, - 0x115547, - 0xded04, - 0x6c144, - 0x20a803, - 0x189a46, - 0x194584, - 0x6d9c3, - 0x216603, - 0x2f61c4, - 0x12ea07, - 0x126e09, - 0x10a588, - 0x52c84, - 0x3e006, - 0x8148, - 0x130245, - 0x3fc9, - 0x2f783, - 0x12eb85, - 0x20c302, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x211543, - 0x20ca43, - 0x216603, - 0x2f55c3, - 0x219f82, - 0x9fe08, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x214383, - 0x217b84, - 0x20a803, - 0xca43, - 0x216603, - 0x22c0c3, - 0x232c43, - 0x2db1c4, - 0x228b03, - 0x20a803, - 0x216603, - 0x240986, - 0x232c43, - 0x228b03, - 0x3a183, - 0x6d9c3, - 0x216603, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x20a803, - 0x216603, - 0x12eb85, - 0x11647, - 0x7883, - 0x2f783, - 0x9fe08, - 0x228b03, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x5c743, - 0x20a803, - 0x216603, - 0x5322c0c3, - 0x232c43, - 0x20a803, - 0x216603, - 0x9fe08, + 0x48d4b, + 0x4908b, + 0x4934b, + 0x4978b, + 0x1d2f06, + 0x308003, + 0xf3605, + 0x68a44, + 0x210983, + 0x1182c7, + 0xe6d44, + 0x6cbc4, + 0x21a3c3, + 0x78a86, + 0x5684, + 0x1b4103, + 0x242543, + 0x2fe7c4, + 0x12bcc7, + 0x14f889, + 0x10fc08, + 0x1b44c4, + 0x1c8a44, + 0x365c6, + 0xa788, + 0x16a605, + 0x8649, + 0x2fb03, + 0x139b05, + 0x201242, + 0x214a83, + 0x232dc3, + 0x308003, + 0x23c803, + 0x203dc3, + 0x242543, + 0x2fdbc3, + 0x233442, + 0x9a048, + 0x214a83, + 0x232dc3, + 0x308003, + 0x21bac3, + 0x219a04, + 0x21a3c3, + 0x3dc3, + 0x242543, + 0x214a83, + 0x232dc3, + 0x2e3504, + 0x308003, + 0x21a3c3, + 0x242543, + 0x2431c6, + 0x232dc3, + 0x308003, + 0x10e83, + 0x1b4103, + 0x242543, + 0x214a83, + 0x232dc3, + 0x308003, + 0x21a3c3, + 0x242543, + 0x139b05, + 0xd1407, + 0x3103, + 0x2fb03, + 0x9a048, + 0x308003, + 0x214a83, + 0x232dc3, + 0x308003, + 0x5cf43, + 0x21a3c3, + 0x242543, + 0x55214a83, + 0x232dc3, + 0x21a3c3, + 0x242543, + 0x9a048, 0x2000c2, - 0x20c302, - 0x22c0c3, - 0x228b03, - 0x20a803, + 0x201242, + 0x214a83, + 0x308003, + 0x21a3c3, 0x2003c2, - 0x216603, - 0x33aec7, - 0x20f64b, - 0x20c003, - 0x278c08, - 0x32d8c7, - 0x32a1c6, - 0x20d0c5, - 0x3291c9, - 0x2112c8, - 0x37b649, - 0x3a1d90, - 0x37b64b, - 0x2e1b49, - 0x207883, - 0x2ef2c9, - 0x230a06, - 0x230a0c, - 0x3977c8, - 0x3d80c8, - 0x2bde09, - 0x2ba48e, - 0x2bd70b, - 0x2fff4c, - 0x225843, - 0x28768c, - 0x3ce3c9, - 0x308907, - 0x232b8c, - 0x2b18ca, - 0x249f84, - 0x30810d, - 0x287548, - 0x3cee4d, - 0x314846, - 0x24224b, - 0x326f89, - 0x388e87, - 0x369a86, - 0x373a89, - 0x2f790a, - 0x3dcf08, - 0x2f4c84, - 0x38e347, - 0x2417c7, - 0x345784, - 0x217304, - 0x344509, - 0x251789, - 0x28c008, - 0x2eda85, - 0x2084c5, - 0x204c46, - 0x307fc9, - 0x26210d, - 0x215348, - 0x204b47, - 0x20d148, - 0x263e46, - 0x237b84, - 0x285845, - 0x3c4c46, - 0x3c5d44, - 0x3ce2c7, - 0x3d558a, - 0x20ab44, - 0x213006, - 0x213cc9, - 0x213ccf, - 0x214b0d, - 0x215b86, - 0x21c110, - 0x21c506, - 0x21dac7, - 0x220607, - 0x22060f, - 0x221349, - 0x226486, - 0x226fc7, - 0x226fc8, - 0x227ac9, - 0x3a8b48, - 0x311007, - 0x20b383, - 0x22bf46, - 0x298fc8, - 0x2ba74a, - 0x2094c9, - 0x211403, - 0x328f86, - 0x2618ca, - 0x23a747, - 0x30874a, - 0x34018e, - 0x221486, - 0x318947, - 0x34f706, - 0x240d86, - 0x20748b, - 0x39710a, - 0x27630d, - 0x212347, - 0x265388, - 0x265389, - 0x26538f, - 0x30440c, - 0x263289, - 0x3d28ce, - 0x322f4a, - 0x3c2b46, - 0x2fdb86, - 0x31ef4c, - 0x32018c, - 0x322208, - 0x35a347, - 0x37c545, - 0x2297c4, - 0x36a6ce, - 0x262584, - 0x329687, - 0x39d78a, - 0x3d3b54, - 0x3d64cf, - 0x2207c8, - 0x22be08, - 0x3625cd, - 0x3625ce, - 0x22c289, - 0x22d408, - 0x22d40f, - 0x23288c, - 0x23288f, - 0x233a47, - 0x235f0a, - 0x23d64b, - 0x237788, - 0x238b87, - 0x25bfcd, - 0x330106, - 0x3082c6, - 0x23b289, - 0x3dbb88, - 0x240b88, - 0x240b8e, - 0x20f747, - 0x2fbb45, - 0x242505, - 0x207a84, - 0x32a486, - 0x28bf08, - 0x374883, - 0x2e16ce, - 0x25c388, - 0x2a704b, - 0x26fd07, - 0x26ae45, - 0x287806, - 0x2aeb47, - 0x31b4c8, - 0x34b8c9, - 0x3cc205, - 0x287c88, - 0x222e86, - 0x3a35ca, - 0x36a5c9, - 0x232c49, - 0x232c4b, - 0x339748, - 0x345649, - 0x2edb46, - 0x28f0ca, - 0x36764a, - 0x23610c, - 0x368807, - 0x26c50a, - 0x2e5b0b, - 0x2e5b19, - 0x324888, - 0x240a05, - 0x25c186, - 0x217d09, - 0x26cc06, - 0x236d8a, - 0x2114c6, - 0x20d644, - 0x2cbb0d, - 0x344147, - 0x20d649, - 0x244745, - 0x245148, - 0x2472c9, - 0x249204, - 0x249e87, - 0x249e88, - 0x24a2c7, - 0x264208, - 0x24ef47, - 0x36bfc5, - 0x256e4c, - 0x257309, - 0x2d908a, - 0x3a6609, - 0x2ef3c9, - 0x3889cc, - 0x25a18b, - 0x25ad08, - 0x25c8c8, - 0x260284, - 0x284fc8, - 0x286209, - 0x2b1987, - 0x213f06, - 0x2a0e07, - 0x29bc49, - 0x20624b, - 0x35cd07, - 0x216687, - 0x3c5247, - 0x3cedc4, - 0x3cedc5, - 0x2daec5, - 0x358e8b, - 0x3b40c4, - 0x326948, - 0x2f9a0a, - 0x222f47, - 0x3c8e87, - 0x290552, - 0x292586, - 0x22f446, - 0x28e40e, - 0x296b86, - 0x296008, - 0x29664f, - 0x3cf208, - 0x3b1148, - 0x34200a, - 0x342011, - 0x2a5c4e, - 0x2536ca, - 0x2536cc, - 0x22d607, - 0x22d610, - 0x3bee08, - 0x2a5e45, - 0x2aee4a, - 0x3c5d8c, - 0x29868d, - 0x3b0c46, - 0x3b0c47, - 0x3b0c4c, - 0x3bd2cc, - 0x36f70c, - 0x2c4c4b, - 0x38c184, - 0x2e5bc4, - 0x2b1189, - 0x34abc7, - 0x37d789, - 0x367489, - 0x2b1587, - 0x2b1746, - 0x2b1749, - 0x2b1b43, - 0x2c660a, - 0x373cc7, - 0x3c05cb, - 0x27618a, - 0x388144, - 0x32fd06, - 0x282349, - 0x36c284, - 0x2f480a, - 0x245005, - 0x2c16c5, - 0x2c16cd, - 0x2c1a0e, - 0x2c1585, - 0x339b86, - 0x240587, - 0x3db90a, - 0x2569c6, - 0x37c044, - 0x30ed87, - 0x2ee38b, - 0x263f07, - 0x24aac4, - 0x27a306, - 0x27a30d, - 0x2dd88c, - 0x20a6c6, - 0x21554a, - 0x229886, - 0x2147c8, - 0x35b747, - 0x2c93ca, - 0x23b006, - 0x212243, - 0x220286, - 0x298e48, - 0x22fb0a, - 0x2d2dc7, - 0x2d2dc8, - 0x25af84, - 0x290ac7, - 0x2d3288, - 0x292788, - 0x2f1b08, - 0x2b808a, - 0x2e2a45, - 0x2db407, - 0x253513, - 0x268f86, - 0x3dabc8, - 0x224609, - 0x240088, - 0x2ff44b, - 0x3a4bc8, - 0x2b92c4, - 0x21aac6, - 0x320906, - 0x31c309, - 0x2c9207, - 0x256f48, - 0x2a1c06, + 0x242543, + 0x336987, + 0x2cd68b, + 0x20dcc3, + 0x2cfac8, + 0x32ab87, + 0x3de706, + 0x218c05, + 0x343189, + 0x242f48, + 0x3359c9, + 0x3359d0, + 0x37ab8b, + 0x2e7589, + 0x203103, + 0x2f8bc9, + 0x231506, + 0x23150c, + 0x335bc8, + 0x3db448, + 0x374789, + 0x2c368e, + 0x37408b, + 0x2ba58c, + 0x220dc3, + 0x28c68c, + 0x3d8f49, + 0x23bb47, + 0x232d0c, + 0x2b858a, + 0x24c0c4, + 0x2ee78d, + 0x28c548, + 0x3ba7cd, + 0x3a6cc6, + 0x2d368b, + 0x34fa09, + 0x3892c7, + 0x295946, + 0x267b49, + 0x33b64a, + 0x30c108, + 0x2fd7c4, + 0x2b5a07, + 0x3c51c7, + 0x204684, + 0x223804, + 0x201fc9, + 0x286ac9, + 0x3d9ac8, + 0x398bc5, + 0x20b285, + 0x2068c6, + 0x2ee649, + 0x25318d, + 0x24c488, + 0x2067c7, + 0x218c88, + 0x2355c6, + 0x239c04, + 0x284405, + 0x3cfb46, + 0x3d1e84, + 0x3d8e47, + 0x3e094a, + 0x20d384, + 0x211846, + 0x2124c9, + 0x2124cf, + 0x212a8d, + 0x213306, + 0x21ca10, + 0x21ce06, + 0x21df07, + 0x21e987, + 0x21e98f, + 0x21f1c9, + 0x225986, + 0x227207, + 0x227208, + 0x2275c9, + 0x3ba588, + 0x305c87, + 0x20ed43, + 0x3d87c6, + 0x29d1c8, + 0x2c394a, + 0x215849, + 0x243083, + 0x342f46, + 0x37f98a, + 0x2f9f87, + 0x23b98a, + 0x31458e, + 0x21f306, + 0x338547, + 0x238886, + 0x2435c6, + 0x3d300b, + 0x39964a, + 0x2cdccd, + 0x2d2107, + 0x266688, + 0x266689, + 0x26668f, + 0x3070cc, + 0x34b789, + 0x27e48e, + 0x2138ca, + 0x216406, + 0x2f4806, + 0x3adc8c, + 0x31fdcc, + 0x320308, + 0x35a487, + 0x235185, + 0x3c8ac4, + 0x28918e, + 0x3a6744, + 0x201247, + 0x39dcca, + 0x3ab1d4, + 0x3d548f, + 0x21eb48, + 0x3d8688, + 0x378c8d, + 0x378c8e, + 0x22cd09, + 0x22e548, + 0x22e54f, + 0x232a0c, + 0x232a0f, + 0x233bc7, + 0x23714a, + 0x3087cb, + 0x239808, + 0x23b107, + 0x25c7cd, + 0x3620c6, + 0x2ee946, + 0x23d449, + 0x22ba08, + 0x2433c8, + 0x2433ce, + 0x2b7687, + 0x3043c5, + 0x245385, + 0x202404, + 0x3de9c6, + 0x3d99c8, + 0x296d83, + 0x2e710e, + 0x25cb88, + 0x2aae8b, + 0x26f887, + 0x228c05, + 0x273506, + 0x2b2b07, + 0x31b348, + 0x36a409, + 0x3cd545, + 0x285c48, + 0x2209c6, + 0x3a618a, + 0x289089, + 0x232dc9, + 0x232dcb, + 0x25d908, + 0x204549, + 0x398c86, + 0x3c5a8a, + 0x2bfe4a, + 0x23734c, + 0x3488c7, + 0x26cf8a, + 0x3b1fcb, + 0x3b1fd9, + 0x324208, + 0x243245, + 0x25c986, + 0x2a0049, + 0x39f606, + 0x219aca, + 0x26e286, + 0x2196c4, + 0x2d604d, + 0x3458c7, + 0x2196c9, + 0x247105, + 0x247ac8, + 0x248009, + 0x24b904, + 0x24bfc7, + 0x24bfc8, + 0x24cc87, + 0x265c08, + 0x250dc7, + 0x2d8b85, + 0x257e8c, + 0x258349, + 0x33144a, + 0x3a8e89, + 0x2f8cc9, + 0x388e0c, + 0x25b4cb, + 0x25c008, + 0x25d0c8, + 0x260cc4, + 0x283b88, + 0x284d09, + 0x2b8647, + 0x212706, + 0x2a43c7, + 0x29fd49, + 0x24768b, + 0x36aa87, + 0x2947c7, + 0x3d0147, + 0x3ba744, + 0x3ba745, + 0x2e3205, + 0x358b4b, + 0x33d684, + 0x323a88, + 0x30060a, + 0x220a87, + 0x3caac7, + 0x28f6d2, + 0x291646, + 0x22f7c6, + 0x28870e, + 0x29ab46, + 0x299288, + 0x29a60f, + 0x3bab88, + 0x28a808, + 0x2dd1ca, + 0x2dd1d1, + 0x2a98ce, + 0x25514a, + 0x25514c, + 0x22e747, + 0x22e750, + 0x3c7108, + 0x2a9ac5, + 0x2b2e0a, + 0x3d1ecc, + 0x29c88d, + 0x3c7c86, + 0x3c7c87, + 0x3c7c8c, + 0x3d2b8c, + 0x21bc8c, + 0x3bd6cb, + 0x38b644, + 0x226204, + 0x2b6f89, + 0x34b147, + 0x37d009, + 0x2bfc89, + 0x2b8247, + 0x2b8406, + 0x2b8409, + 0x2b8803, + 0x2b314a, + 0x2961c7, + 0x3c8e0b, + 0x2cdb4a, + 0x22de04, + 0x32f4c6, + 0x280e09, + 0x35c004, + 0x2df48a, + 0x2e0685, + 0x2c7945, + 0x2c794d, + 0x2c7c8e, + 0x2c7805, + 0x335046, + 0x242dc7, + 0x22b78a, + 0x3a6a46, + 0x37bc84, + 0x3cdb87, + 0x2fab0b, + 0x265907, + 0x262944, + 0x3a39c6, + 0x3a39cd, + 0x2e568c, + 0x21a286, + 0x24c68a, + 0x34ca86, + 0x21e648, + 0x30c487, + 0x2d3b8a, + 0x23c486, + 0x27d903, + 0x2f3886, + 0x29d048, + 0x245aca, + 0x2dcc07, + 0x2dcc08, + 0x249ac4, + 0x28fc47, + 0x2f4348, + 0x291848, + 0x2bbdc8, + 0x2ffc0a, + 0x2ec0c5, + 0x2c1ac7, + 0x254f93, + 0x26b2c6, + 0x24aec8, + 0x221589, + 0x2428c8, + 0x33c58b, + 0x385308, + 0x2c02c4, + 0x21a706, + 0x320c06, + 0x3186c9, + 0x2d39c7, + 0x257f88, + 0x2a51c6, 0x200bc4, - 0x3a0e45, - 0x2cf888, - 0x201d8a, - 0x2cb788, - 0x2d0846, - 0x29cd0a, - 0x26e708, - 0x2d4888, - 0x2d6288, - 0x2d6ac6, - 0x2d9646, - 0x3a60cc, - 0x2d9bd0, - 0x2ade05, - 0x3b6408, - 0x3b6410, - 0x3cf010, - 0x3a1c0e, - 0x3a5d4e, - 0x3a5d54, - 0x3ad7cf, - 0x3adb86, - 0x345851, - 0x343a93, - 0x343f08, - 0x369c05, - 0x27aa88, - 0x2097c5, - 0x329d8c, - 0x229189, - 0x229609, - 0x3dd547, - 0x340649, - 0x236947, - 0x35e746, - 0x285647, - 0x203885, - 0x2080c3, - 0x23a183, - 0x20fc44, - 0x30128d, - 0x34bc8f, + 0x208405, + 0x3a3188, + 0x344e4a, + 0x2d5cc8, + 0x2dad46, + 0x2a0f0a, + 0x269f88, + 0x2de248, + 0x2df708, + 0x2dff46, + 0x2e1e86, + 0x3a4d0c, + 0x2e2410, + 0x2cc145, + 0x2230c8, + 0x2230d0, + 0x3ba990, + 0x33584e, + 0x3a498e, + 0x3a4994, + 0x3a804f, + 0x3a8406, + 0x3dbe51, + 0x345213, + 0x345688, + 0x2035c5, + 0x2d0008, + 0x3a05c5, + 0x33f34c, + 0x229f09, + 0x3a6589, + 0x356947, + 0x26c649, + 0x39f1c7, + 0x334686, + 0x284207, + 0x204c05, + 0x20a9c3, + 0x210e83, + 0x213404, + 0x36adcd, + 0x3c304f, 0x200c05, - 0x333a46, - 0x212887, - 0x397547, - 0x204206, - 0x20420b, - 0x2a6a85, - 0x258b46, - 0x305f87, - 0x24f449, - 0x2211c6, - 0x3855c5, - 0x3ba74b, - 0x3b0946, - 0x2137c5, - 0x23f088, - 0x291988, - 0x29f94c, - 0x29f950, - 0x2a2749, - 0x2b71c7, - 0x2b22cb, - 0x2c1f86, - 0x310eca, - 0x3da94b, - 0x30cc4a, - 0x2eca86, - 0x2ed205, - 0x32d7c6, - 0x286bc8, - 0x3dd60a, - 0x36225c, - 0x2f568c, - 0x2f5988, - 0x240985, - 0x38b9c7, - 0x2ba0c6, - 0x3b9505, - 0x218086, - 0x2043c8, - 0x2c0647, - 0x2ba388, - 0x26904a, - 0x3a978c, - 0x374b09, - 0x3a9a07, - 0x286744, - 0x2425c6, - 0x300b4a, - 0x367585, - 0x216f8c, - 0x21a0c8, - 0x2e4ac8, - 0x34ea0c, - 0x35a64c, - 0x387c89, - 0x387ec7, - 0x370b8c, - 0x222104, - 0x24a04a, - 0x30f80c, - 0x25038b, - 0x250a0b, - 0x253c46, - 0x256b07, - 0x22d847, - 0x22d84f, - 0x309cd1, - 0x2dfa92, - 0x257bcd, - 0x257bce, - 0x257f0e, - 0x3ad988, - 0x3ad992, - 0x260408, - 0x224c47, - 0x24d44a, - 0x2a95c8, - 0x296b45, - 0x2b484a, - 0x21c887, - 0x2e99c4, - 0x201783, - 0x235b45, - 0x342287, - 0x355047, - 0x29888e, - 0x3355cd, - 0x33c809, - 0x319c85, - 0x358243, - 0x34a646, - 0x259145, - 0x2a7288, - 0x21e489, - 0x25c1c5, - 0x25c1cf, - 0x2d2547, - 0x20cf45, - 0x2706ca, - 0x3c1586, - 0x245e09, - 0x37818c, - 0x3addc9, - 0x3d7046, - 0x2f980c, - 0x3390c6, - 0x307648, - 0x2e5a06, - 0x3645c6, - 0x2b5844, - 0x31c283, - 0x221a4a, - 0x3037d1, - 0x26344a, - 0x246685, - 0x25a5c7, - 0x254047, - 0x2d3384, - 0x2d338b, - 0x21d048, - 0x2bf146, - 0x2315c5, - 0x32b944, - 0x2410c9, + 0x33f246, + 0x20cb87, + 0x399a87, + 0x208886, + 0x20888b, + 0x2aa785, + 0x259fc6, + 0x30be47, + 0x251ac9, + 0x229b46, + 0x3860c5, + 0x3c910b, + 0x3d6e86, + 0x21d685, + 0x241588, + 0x290b08, + 0x299b8c, + 0x299b90, + 0x2ac2c9, + 0x2c15c7, + 0x2b918b, + 0x2c8206, + 0x305b4a, + 0x36ff8b, + 0x31b58a, + 0x398806, + 0x2f6fc5, + 0x32aa86, + 0x279f48, + 0x356a0a, + 0x37891c, + 0x2fdc8c, + 0x2fdf88, + 0x2431c5, + 0x382747, + 0x24a006, + 0x24aac5, + 0x2177c6, + 0x208a48, + 0x2c6747, + 0x2c3588, + 0x26b38a, + 0x3b954c, + 0x297009, + 0x3b97c7, + 0x285244, + 0x245446, + 0x28a38a, + 0x2bfd85, + 0x22348c, + 0x223b48, + 0x26a208, + 0x2aebcc, + 0x38878c, + 0x22d949, + 0x22db87, + 0x25494c, + 0x3082c4, + 0x3713ca, + 0x30de8c, + 0x24fdcb, + 0x25044b, + 0x252b06, + 0x256447, + 0x22e987, + 0x22e98f, + 0x30f351, + 0x2e8d92, + 0x258c0d, + 0x258c0e, + 0x258f4e, + 0x3a8208, + 0x3a8212, + 0x25be08, + 0x221bc7, + 0x24ec0a, + 0x2ac988, + 0x29ab05, + 0x2bb28a, + 0x21d187, + 0x2ef184, + 0x210883, + 0x236085, + 0x2dd447, + 0x30d3c7, + 0x29ca8e, + 0x352e8d, + 0x354009, + 0x302905, + 0x361043, + 0x34a886, + 0x25a5c5, + 0x2ab0c8, + 0x224249, + 0x25c9c5, + 0x25c9cf, + 0x2e0b07, + 0x218a85, + 0x27024a, + 0x3d0b06, + 0x312b09, + 0x381b4c, + 0x3ce889, + 0x2062c6, + 0x30040c, + 0x32dd86, + 0x30cfc8, + 0x3b1ec6, + 0x365486, + 0x2bc1c4, + 0x31d203, + 0x21124a, + 0x227e11, + 0x34b94a, + 0x23ea05, + 0x25b907, + 0x2559c7, + 0x2e6f04, + 0x2f444b, + 0x33aa48, + 0x2c55c6, + 0x361785, + 0x261f44, + 0x3828c9, 0x2008c4, - 0x20c3c7, - 0x34cf05, - 0x34cf07, - 0x28e645, - 0x247d03, - 0x224b08, - 0x27ac8a, - 0x24e4c3, - 0x39774a, - 0x36c746, - 0x25bf4f, - 0x3d2009, - 0x2e1650, - 0x2fcbc8, - 0x2d1689, - 0x29a087, - 0x27a28f, - 0x38f304, - 0x2db244, - 0x21c386, - 0x243206, - 0x2ed5ca, - 0x252f86, - 0x395207, - 0x311348, - 0x311547, - 0x312a07, - 0x314aca, - 0x31330b, - 0x251a45, - 0x2df6c8, - 0x20ae83, - 0x3bcd4c, - 0x37c2cf, - 0x3c0d8d, - 0x257747, - 0x33c949, - 0x2312c7, - 0x267e48, - 0x3d3d4c, - 0x2b91c8, - 0x246388, - 0x33104e, - 0x348c94, - 0x3491a4, - 0x35ff0a, - 0x37bccb, - 0x236a04, - 0x236a09, - 0x2b5448, - 0x242d05, - 0x37438a, - 0x285b07, - 0x322c44, - 0x248343, - 0x22c0c3, - 0x235604, - 0x232c43, - 0x228b03, - 0x224e44, - 0x214543, - 0x211543, - 0x2d9bc6, - 0x217b84, - 0x20a803, - 0x216603, - 0x216103, + 0x20e087, + 0x37a385, + 0x37a387, + 0x288945, + 0x3801c3, + 0x221a88, + 0x2d020a, + 0x23db43, + 0x399c8a, + 0x2a74c6, + 0x25c74f, + 0x2b7609, + 0x2e7090, + 0x305748, + 0x2db3c9, + 0x29df47, + 0x3a394f, + 0x3905c4, + 0x2e3584, + 0x203946, + 0x2344c6, + 0x2ef40a, + 0x254686, + 0x2b5e07, + 0x315048, + 0x315247, + 0x3166c7, + 0x31784a, + 0x316fcb, + 0x33bf85, + 0x2e89c8, + 0x201343, + 0x3bb3cc, + 0x3965cf, + 0x234f8d, + 0x258787, + 0x354149, + 0x357087, + 0x2401c8, + 0x3ab3cc, + 0x2c01c8, + 0x23e708, + 0x32c9ce, + 0x341b94, + 0x3420a4, + 0x36080a, + 0x37b90b, + 0x39f284, + 0x39f289, + 0x331e88, + 0x245d85, + 0x29688a, + 0x291087, + 0x2135c4, + 0x202703, + 0x214a83, + 0x235b44, + 0x232dc3, + 0x308003, + 0x221dc4, + 0x21bc83, + 0x23c803, + 0x2e2406, + 0x219a04, + 0x21a3c3, + 0x242543, + 0x2141c3, 0x2000c2, - 0x248343, - 0x20c302, - 0x22c0c3, - 0x235604, - 0x232c43, - 0x228b03, - 0x214543, - 0x2d9bc6, - 0x20a803, - 0x216603, - 0x9fe08, - 0x22c0c3, - 0x232c43, - 0x212483, - 0x20a803, - 0x6d9c3, - 0x216603, - 0x9fe08, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x211543, - 0x217b84, - 0x20a803, - 0x216603, + 0x202703, + 0x201242, + 0x214a83, + 0x235b44, + 0x232dc3, + 0x308003, + 0x21bc83, + 0x2e2406, + 0x21a3c3, + 0x242543, + 0x9a048, + 0x214a83, + 0x232dc3, + 0x228503, + 0x21a3c3, + 0x1b4103, + 0x242543, + 0x9a048, + 0x214a83, + 0x232dc3, + 0x308003, + 0x23c803, + 0x219a04, + 0x21a3c3, + 0x242543, 0x2000c2, - 0x258783, - 0x20c302, - 0x232c43, - 0x228b03, - 0x211543, - 0x20a803, - 0x216603, - 0x204042, - 0x209382, - 0x20c302, - 0x22c0c3, - 0x207902, + 0x27ee03, + 0x201242, + 0x232dc3, + 0x308003, + 0x23c803, + 0x21a3c3, + 0x242543, + 0x2086c2, + 0x215702, + 0x201242, + 0x214a83, + 0x208c02, 0x2005c2, - 0x224e44, - 0x303f84, - 0x22b302, - 0x217b84, + 0x221dc4, + 0x306c44, + 0x223f82, + 0x219a04, 0x2003c2, - 0x216603, - 0x216103, - 0x253c46, - 0x20ff42, - 0x205402, - 0x225242, - 0x55a08683, - 0x55e2d603, - 0x54b86, - 0x54b86, - 0x242244, - 0x20ca43, - 0x14114d, - 0x8bd8a, - 0x1bc1cc, - 0x1b338c, - 0xca7cd, - 0x12eb85, - 0x8b50c, - 0x6bb47, - 0xbec6, - 0x15d08, - 0x1ae07, - 0x21ec8, - 0x19974a, - 0x10f087, - 0x56a8b745, - 0xdc1c9, - 0x56c344cb, - 0x920b, - 0x1846c8, - 0x14dd89, - 0x6828a, - 0xe56ce, - 0x7d4d, - 0x2c28d, - 0x143fe8b, - 0xdd74a, - 0xd944, - 0x58c86, - 0x1bd708, - 0x18a0c8, - 0x67607, - 0xa0c5, - 0xfdc7, - 0x330c9, - 0x16c307, - 0xe688, - 0x2b5c9, - 0x4a444, - 0x4d185, - 0x13fe4e, - 0x189d4d, - 0x114c8, - 0x57293106, - 0x57d72f88, - 0x74388, - 0x13b0d0, - 0x510cc, - 0x60fc7, - 0x62447, - 0x68607, - 0x71487, - 0x4c02, - 0x122587, - 0x1972cc, - 0xfe445, - 0x35147, - 0xa8946, - 0xaa289, - 0xac0c8, - 0x4742, + 0x242543, + 0x2141c3, + 0x252b06, + 0x20c782, + 0x201b82, + 0x2221c2, + 0x57a07403, + 0x57e2e743, + 0x56246, + 0x56246, + 0x2d3684, + 0x203dc3, + 0x160d, + 0x1d984a, + 0x16300c, + 0x1d76cc, + 0xd4ecd, + 0x139b05, + 0x86209, + 0x8d2cc, + 0x29907, + 0xdb86, + 0x13dc8, + 0x1bf87, + 0x201c8, + 0x1ac0ca, + 0x10d707, + 0x58a8d505, + 0xe4f09, + 0x58c3480b, + 0x125c08, + 0x1558b, + 0x12c5c8, + 0x1c48c9, + 0x4060a, + 0x1b1b8e, + 0x1d158d, + 0x2cd0d, + 0x14426cb, + 0xe554a, + 0x8d04, + 0x5a106, + 0x19b808, + 0x79108, + 0x25687, + 0x1d35c5, + 0xc607, + 0x33249, + 0x15c087, + 0x106c8, + 0x26a89, + 0x4ce04, + 0x4e945, + 0x98e8e, + 0x12c207, + 0x59225a86, + 0x78d8d, + 0xd1288, + 0x59694f86, + 0x5a094f88, + 0x56f88, + 0x136b90, + 0x53f8c, + 0x61b47, + 0x62347, + 0x6a947, + 0x72047, + 0x6882, + 0x120687, + 0x19980c, + 0x13c945, + 0x107c07, + 0xac186, + 0xacdc9, + 0xaff88, + 0x6502, 0x5c2, - 0x18ce06, - 0x1ba00b, - 0x1ba306, - 0xbe384, - 0x1753c7, - 0xe3389, - 0x6dc89, - 0x1432c8, - 0x48902, - 0x191f89, - 0xbac8, - 0xe9a8a, - 0x38909, - 0x52946, - 0xce3c9, - 0xdd6c7, - 0xdde09, - 0xdef08, - 0xe0f87, - 0xe29c9, - 0xe8ec5, - 0xe9250, - 0x155886, - 0x175305, - 0x114587, - 0x3950d, - 0x3ef85, - 0xef1c6, - 0xef9c7, - 0xf61d8, - 0x11848, - 0xbe7ca, - 0xa982, - 0x507ca, - 0x6284d, - 0x2e42, - 0x13686, - 0x9d488, - 0xabe4a, - 0x45948, - 0x6d309, - 0x111788, - 0x7768e, - 0x6d548, - 0x14a647, - 0x58293044, - 0x14e70d, - 0x102f05, - 0x3148, - 0x42dc8, - 0x10c246, - 0x14302, - 0x92c04, - 0x62706, - 0x3e006, - 0x58532e4b, - 0x57c2, + 0x18d986, + 0x1b9ecb, + 0x1ba1c6, + 0x174d04, + 0x978c7, + 0x41a89, + 0xf0c09, + 0x1b1148, + 0x49582, + 0x193a49, + 0xd788, + 0xef24a, + 0x15adc9, + 0x1b4186, + 0xd8949, + 0xe54c7, + 0xe5c09, + 0xe7ac8, + 0xea3c7, + 0xec049, + 0xf0005, + 0xf1210, + 0x1b6786, + 0x97805, + 0x91487, + 0xec74d, + 0x41485, + 0xf8ac6, + 0xf92c7, + 0xfe7d8, + 0xd1608, + 0x13db8a, + 0xca42, + 0x5020a, + 0x60e4d, + 0x45c2, + 0xce946, + 0x11ec6, + 0xa1788, + 0xafd0a, + 0x472c8, + 0x6de89, + 0x115488, + 0x6eace, + 0x6e0c8, + 0x14a887, + 0x5a694ec4, + 0xae8cd, + 0x10a085, + 0x69148, + 0x34088, + 0x111b86, + 0xc2c2, + 0xc53c4, + 0xe2c06, + 0x365c6, + 0x5a8ef74b, + 0x1442, 0x401, 0x81, - 0x5a947, - 0x8d9c3, - 0x576f67c4, - 0x57a973c3, + 0xb8f08, + 0x5bc87, + 0x150503, + 0x59a37f04, + 0x59e9b383, 0xc1, - 0x1a286, + 0xf586, 0xc1, 0x201, - 0x1a286, - 0x8d9c3, - 0x422c3, - 0x46e44, - 0x14947, - 0x5b07, - 0x153e145, - 0x4cec4, - 0x61107, - 0xc302, - 0x249f84, - 0x22c0c3, - 0x24b304, - 0x224e44, - 0x20a803, - 0x2244c5, - 0x216e03, - 0x236bc3, - 0x204185, - 0x205b03, - 0xdd43, - 0x5962c0c3, - 0x232c43, - 0x4b304, - 0x20c3, - 0x228b03, + 0xf586, + 0x150503, + 0x66603, + 0x647c4, + 0x1e7c7, + 0x7787, + 0x15c27c5, + 0x4e684, + 0x13d707, + 0x1242, + 0x24c0c4, + 0x214a83, + 0x24d9c4, + 0x221dc4, + 0x21a3c3, + 0x221445, + 0x214903, + 0x22b983, + 0x208805, + 0x207783, + 0x1243, + 0x5ba14a83, + 0x232dc3, + 0x4d9c4, + 0x7083, + 0x308003, 0x200181, - 0xe403, - 0x211543, - 0x303f84, - 0x217b84, - 0x20a803, - 0x4bbc3, - 0x216603, - 0x20c603, - 0x9fe08, + 0x1a8c3, + 0x23c803, + 0x306c44, + 0x219a04, + 0x21a3c3, + 0x4e283, + 0x242543, + 0x20e2c3, + 0x9a048, 0x2000c2, - 0x248343, - 0x20c302, - 0x22c0c3, - 0x232c43, - 0x212483, + 0x202703, + 0x201242, + 0x214a83, + 0x232dc3, + 0x228503, 0x2005c2, - 0x224e44, - 0x214543, - 0x211543, - 0x20a803, - 0x20ca43, - 0x216603, - 0x205b03, - 0x17c204, - 0x9fe08, - 0x103c87, - 0xc302, - 0x1a0dc5, - 0x5120f, - 0xd23c6, - 0x14470c8, - 0x11240e, - 0x5a631802, - 0x32ce48, - 0x28c4c6, - 0x24d046, - 0x30e787, - 0x5aa00c82, - 0x5afd1e88, - 0x21068a, - 0x260a48, + 0x221dc4, + 0x21bc83, + 0x23c803, + 0x21a3c3, + 0x203dc3, + 0x242543, + 0x207783, + 0x196504, + 0x9a048, + 0x106947, + 0x1242, + 0x1a3105, + 0x540cf, + 0xe0986, + 0x144ca88, + 0x1160ce, + 0x5ca345c2, + 0x297ac8, + 0x35c5c6, + 0x24e806, + 0x395e87, + 0x5ce00c82, + 0x5d2b7488, + 0x20bd4a, + 0x2615c8, 0x200ac2, - 0x3c0409, - 0x251a87, - 0x213e86, - 0x224849, - 0x2db544, - 0x3c0306, - 0x2c7144, - 0x203584, - 0x2560c9, - 0x30f546, - 0x229cc5, - 0x264f45, - 0x22cac7, - 0x2c3887, - 0x2f53c4, - 0x35c0c6, - 0x2f9145, - 0x20e805, - 0x246745, - 0x2c4f47, - 0x26fb45, - 0x247749, - 0x329945, - 0x31b604, - 0x256907, - 0x33ed4e, - 0x343689, - 0x28e2c9, - 0x33de06, - 0x23ce88, - 0x3c208b, - 0x36828c, - 0x324046, - 0x2ffe07, - 0x2b34c5, - 0x21730a, - 0x28c109, - 0x2013c9, - 0x3d9f06, - 0x305d45, - 0x242885, - 0x355449, - 0x2468cb, - 0x2772c6, - 0x354546, - 0x204b44, - 0x239b06, - 0x2fbbc8, - 0x3bc0c6, - 0x2eb006, - 0x3cf9c8, - 0x3d6e47, - 0x3d9cc9, - 0x3de005, - 0x9fe08, - 0x3cc184, - 0x312f84, - 0x208345, - 0x346b09, - 0x222c07, - 0x222c0b, - 0x225a4a, - 0x2290c5, - 0x5b20b382, - 0x20ebc7, - 0x5b6293c8, - 0x328887, - 0x2dd185, - 0x347e8a, - 0xc302, - 0x2795cb, - 0x27deca, - 0x247bc6, - 0x2081c3, - 0x291f0d, - 0x3c084c, - 0x3c1acd, - 0x2304c5, - 0x27cb85, - 0x3748c7, - 0x207909, - 0x210586, - 0x252e05, - 0x2ec888, - 0x239a03, - 0x2e2ec8, - 0x239a08, - 0x2c8907, - 0x369588, - 0x3afa49, - 0x2fb787, - 0x20f1c7, - 0x33dfc8, - 0x29b484, - 0x29b487, - 0x314748, - 0x360586, - 0x3c3e4f, - 0x22a5c7, - 0x35bbc6, - 0x388005, - 0x2253c3, - 0x243c47, - 0x3874c3, - 0x24a686, - 0x24cdc6, - 0x24db06, - 0x294d45, - 0x264203, - 0x391c08, - 0x38a8c9, - 0x39a24b, - 0x24dc88, - 0x24ec05, - 0x24fe45, - 0x5bab12c2, - 0x285709, - 0x224ec7, - 0x258bc5, - 0x255fc7, - 0x257a86, - 0x3804c5, - 0x258f8b, - 0x25ad04, - 0x260605, - 0x260747, - 0x276c46, - 0x277085, - 0x2851c7, - 0x285cc7, - 0x2d0d84, - 0x28b30a, - 0x28cd48, - 0x3c2349, - 0x394785, - 0x32f406, - 0x2fbd8a, - 0x264e46, - 0x231047, - 0x26c88d, - 0x2a65c9, - 0x390885, - 0x36ac47, - 0x252788, - 0x2f7288, - 0x3a8d07, - 0x3affc6, - 0x2230c7, - 0x24b503, - 0x30f4c4, - 0x37dc05, - 0x3a5447, - 0x3ab0c9, - 0x26b7c8, - 0x230f45, - 0x2530c4, - 0x24de45, - 0x25ca8d, + 0x3c8c49, + 0x33bfc7, + 0x212686, + 0x2217c9, + 0x2c1c04, + 0x3c8b46, + 0x2cc7c4, + 0x20e904, + 0x257889, + 0x30dbc6, + 0x265445, + 0x266245, + 0x22d547, + 0x2dbd87, + 0x34c8c4, + 0x31e606, + 0x2ff485, + 0x210845, + 0x23eac5, + 0x3bd9c7, + 0x26f6c5, + 0x248489, + 0x343fc5, + 0x31b484, + 0x3a6987, + 0x36344e, + 0x2031c9, + 0x2885c9, + 0x348706, + 0x23f9c8, + 0x36f2cb, + 0x2a5a0c, + 0x322686, + 0x2ba447, + 0x2eee85, + 0x3270ca, + 0x3d9bc9, + 0x345c89, + 0x295146, + 0x30bc05, + 0x245705, + 0x36a209, + 0x23ec4b, + 0x2c2246, + 0x352686, + 0x2067c4, + 0x2ecd46, + 0x304448, + 0x3c1e46, + 0x2e3e06, + 0x3dd908, + 0x2019c7, + 0x201d49, + 0x205a85, + 0x9a048, + 0x3cd4c4, + 0x316c44, + 0x20b105, + 0x3403c9, + 0x220747, + 0x22074b, + 0x22284a, + 0x228585, + 0x5d60c282, + 0x2cda07, + 0x5da29cc8, + 0x295387, + 0x301345, + 0x348aca, + 0x1242, + 0x27c58b, + 0x27d98a, + 0x248906, + 0x20a803, + 0x206c8d, + 0x3c4c4c, + 0x3c534d, + 0x230585, + 0x27bbc5, + 0x296dc7, + 0x3d1149, + 0x20bc46, + 0x254505, + 0x37b708, + 0x2ce983, + 0x2e3948, + 0x2ecc48, + 0x383fc7, + 0x3b8a88, + 0x3c0809, + 0x2fd2c7, + 0x2cd207, + 0x3de588, + 0x23ae04, + 0x23ae07, + 0x3a6bc8, + 0x360f06, + 0x3c0ecf, + 0x22a907, + 0x31e106, + 0x22dcc5, + 0x222343, + 0x246287, + 0x387fc3, + 0x24d046, + 0x24e586, + 0x24f0c6, + 0x293d45, + 0x265c03, + 0x3936c8, + 0x38a109, + 0x39bf8b, + 0x24f248, + 0x250a85, + 0x252305, + 0x5de2dec2, + 0x2842c9, + 0x221e47, + 0x25a045, + 0x257787, + 0x258ac6, + 0x381745, + 0x25a40b, + 0x25c004, + 0x261185, + 0x2612c7, + 0x276806, + 0x276c45, + 0x283d87, + 0x2847c7, + 0x2a7484, + 0x28d0ca, + 0x28dbc8, + 0x2ccc09, + 0x23f285, + 0x205886, + 0x30460a, + 0x266146, + 0x2ed087, + 0x26d30d, + 0x2aa2c9, + 0x391c45, + 0x363847, + 0x289708, + 0x303588, + 0x3286c7, + 0x384d06, + 0x21abc7, + 0x24dbc3, + 0x30db44, + 0x37d485, + 0x3a7747, + 0x3b0d49, + 0x229588, + 0x2ecf85, + 0x2425c4, + 0x247ec5, + 0x24f40d, 0x200cc2, - 0x2b6606, - 0x2d7a86, - 0x301bca, - 0x3915c6, - 0x398245, - 0x2c7605, - 0x2c7607, - 0x3a340c, - 0x27420a, - 0x290206, - 0x21fb05, - 0x239946, - 0x290387, - 0x292d06, - 0x294c4c, - 0x224989, - 0x5be1a707, - 0x296a05, - 0x296a06, - 0x296e48, - 0x245785, - 0x2a6d05, - 0x2a7f48, - 0x2a814a, - 0x5c21efc2, - 0x5c606a02, - 0x3ac085, - 0x266803, - 0x23dc88, - 0x245f43, - 0x2a83c4, - 0x245f4b, - 0x368688, + 0x2bca46, + 0x2eaf06, + 0x308cca, + 0x39a786, + 0x3a3345, + 0x26d6c5, + 0x26d6c7, + 0x3a5fcc, + 0x256e0a, + 0x28f246, + 0x2e1d85, + 0x2ecb86, + 0x28f507, + 0x291246, + 0x293c4c, + 0x221909, + 0x5e20fa07, + 0x29a9c5, + 0x29a9c6, + 0x29ae08, + 0x2c4005, + 0x2aab45, + 0x2ab848, + 0x2aba4a, + 0x5e67b8c2, + 0x5ea09e42, + 0x355fc5, + 0x237643, + 0x326008, + 0x228703, + 0x2abcc4, + 0x312c4b, + 0x36f688, + 0x2b9648, + 0x5ef03cc9, + 0x2b1009, + 0x2b19c6, 0x2b2788, - 0x5cae7489, - 0x2ad149, - 0x2adb06, - 0x2ae7c8, - 0x2ae9c9, - 0x2af346, - 0x2af4c5, - 0x244246, - 0x2afa09, - 0x2bf9c7, - 0x3ddac6, - 0x2dd507, - 0x2e77c7, - 0x208804, - 0x5ce11b49, - 0x3b9748, - 0x3d1d88, - 0x267747, - 0x2cb246, - 0x3c6b89, - 0x24d007, - 0x3b8fca, - 0x32f548, - 0x3bd087, - 0x3c1086, - 0x27d88a, - 0x241b88, - 0x2d7505, - 0x228345, - 0x3359c7, - 0x316049, - 0x31828b, - 0x354048, - 0x3299c9, - 0x24e087, - 0x2bae4c, - 0x2bb8cc, - 0x2bbbca, - 0x2bbe4c, - 0x2c6cc8, - 0x2c6ec8, - 0x2c70c4, - 0x2c8089, - 0x2c82c9, - 0x2c850a, - 0x2c8789, - 0x2c8ac7, - 0x3b4f4c, - 0x3c62c6, - 0x26c248, - 0x264f06, - 0x38ebc6, - 0x390787, - 0x39f348, - 0x32a68b, - 0x3da007, - 0x255d89, - 0x25a709, - 0x285907, - 0x2c7384, + 0x2b2989, + 0x2b3806, + 0x2b3985, + 0x246c06, + 0x2b4749, + 0x2c8947, + 0x38e386, + 0x20af47, + 0x345fc7, + 0x207584, + 0x5f2d1909, + 0x24ad08, + 0x2b7388, + 0x2257c7, + 0x2d5946, + 0x3d0f49, + 0x24e7c7, + 0x24a58a, + 0x32ed08, + 0x3bb707, + 0x3d0606, + 0x2f0e0a, + 0x23df48, + 0x2ea985, + 0x227b85, + 0x3cbc87, + 0x3190c9, + 0x31cf0b, + 0x351f08, + 0x344049, + 0x24fb47, + 0x2c2bcc, + 0x2c3bcc, + 0x2c3eca, + 0x2c414c, + 0x2cc348, + 0x2cc548, + 0x2cc744, + 0x2ce109, + 0x2ce349, + 0x2ce58a, + 0x2ce809, + 0x2ceb87, + 0x3bec0c, + 0x3d2406, + 0x26ccc8, + 0x266206, + 0x38fe86, + 0x391b47, + 0x3a1088, + 0x3debcb, + 0x295247, + 0x257549, + 0x25ba49, + 0x2844c7, + 0x2cca04, 0x200fc7, - 0x2cfec6, - 0x20c7c6, - 0x215705, - 0x2ce588, - 0x340544, - 0x340546, - 0x2740cb, - 0x2c6909, - 0x31fc86, - 0x2eb209, - 0x208406, - 0x201f88, - 0x20e503, - 0x305ec5, - 0x21b649, - 0x21bec5, - 0x380d84, - 0x2755c6, - 0x2354c5, - 0x207f06, - 0x316887, - 0x34b4c6, - 0x22ab4b, - 0x28efc7, - 0x243946, - 0x272506, - 0x22cb86, - 0x2f5389, - 0x2b884a, - 0x2f9d45, - 0x22850d, - 0x2a8246, - 0x23aec6, - 0x2e1546, - 0x214745, - 0x2e9547, - 0x26b107, - 0x272c8e, - 0x211543, - 0x2cb209, - 0x374d89, - 0x22c807, - 0x269887, - 0x292905, - 0x36b7c5, - 0x5d34464f, - 0x2d18c7, - 0x2d1a88, - 0x2d1fc4, - 0x2d2286, - 0x5d642582, - 0x2d6d46, - 0x2d9bc6, - 0x374f4e, - 0x2e2d0a, - 0x3d2606, - 0x219b8a, - 0x3c18c9, - 0x23bd85, - 0x307b08, - 0x335886, - 0x2b1388, - 0x3dbd48, - 0x27b58b, - 0x30e885, - 0x26fbc8, - 0x3cfb0c, - 0x2dd047, - 0x24d386, - 0x3dd0c8, - 0x32a348, - 0x5da39242, - 0x208ccb, - 0x3de209, - 0x28bbc9, - 0x21b4c7, - 0x3ba588, - 0x5de07748, - 0x20df8b, - 0x343149, - 0x259e4d, - 0x31d7c8, - 0x27da88, - 0x5e201e02, - 0x3c75c4, - 0x5e62d7c2, - 0x3aba86, - 0x5ea06302, - 0x2f258a, - 0x2a6b86, - 0x26a908, - 0x3be5c8, - 0x3c0206, - 0x300306, - 0x2fc946, - 0x2a7205, - 0x237dc4, - 0x5efd3204, - 0x359686, - 0x2978c7, - 0x5f20bc07, - 0x389b0b, - 0x328a89, - 0x27cbca, - 0x220504, - 0x2c7748, - 0x3dd88d, - 0x2f3a89, - 0x2f3cc8, - 0x2f3f49, - 0x2f61c4, - 0x23d504, - 0x39ba85, - 0x275f4b, - 0x368606, - 0x3594c5, - 0x3cb449, - 0x35c188, - 0x2a4984, - 0x217489, - 0x306845, - 0x2c38c8, - 0x20f887, - 0x28e6c8, - 0x282546, - 0x3a8a07, - 0x2deac9, - 0x3ba8c9, - 0x213845, - 0x322ac5, - 0x5f61df02, - 0x31b3c4, - 0x230705, - 0x30e686, - 0x33cf45, - 0x2b7d87, - 0x2f2ec5, - 0x276c84, - 0x33dec6, - 0x252e87, - 0x251f86, - 0x3ac605, - 0x2098c8, - 0x28c6c5, - 0x20e387, - 0x21d889, - 0x2c6a4a, - 0x227cc7, - 0x227ccc, - 0x229c86, - 0x241d49, - 0x38c685, - 0x2456c8, - 0x202e43, - 0x2edb05, - 0x3a94c5, - 0x27c1c7, - 0x5fa01482, - 0x2ee787, - 0x2e8746, - 0x37fcc6, - 0x2ecbc6, - 0x32a286, - 0x239188, - 0x27abc5, - 0x35bc87, - 0x35bc8d, - 0x201783, - 0x3c6785, - 0x270487, - 0x2eeac8, - 0x270045, - 0x216348, - 0x37d686, - 0x2dc387, - 0x2c9c05, - 0x30e906, - 0x392185, - 0x21034a, - 0x303406, - 0x26ef47, - 0x2c2fc5, - 0x308407, - 0x30ed04, - 0x380d06, - 0x307a45, - 0x397c4b, - 0x2cfd49, - 0x25888a, - 0x2138c8, - 0x38d108, - 0x30bd0c, - 0x30c747, - 0x30fac8, - 0x316608, - 0x3186c5, - 0x3562ca, - 0x358249, - 0x5fe03a42, - 0x206146, - 0x25c1c4, - 0x2f0e09, - 0x25b589, - 0x2712c7, - 0x31d0c7, - 0x367309, - 0x2b8288, - 0x2b828f, - 0x223ac6, - 0x2dbe8b, - 0x259485, - 0x259487, - 0x36c889, - 0x210086, - 0x217407, - 0x2dfe05, - 0x2303c4, - 0x35b606, - 0x222dc4, - 0x2f1347, - 0x321988, - 0x60305c48, - 0x306cc5, - 0x306e07, - 0x324a09, - 0x208a84, - 0x23eb48, - 0x607c2e88, - 0x2d3384, - 0x2ebdc8, - 0x369b44, - 0x34b6c9, - 0x214685, - 0x60a19f82, - 0x223b05, - 0x2e8045, - 0x36aa88, - 0x233887, - 0x60e008c2, - 0x3d3345, - 0x2d4706, - 0x23e306, - 0x31b388, - 0x3192c8, - 0x33cf06, - 0x34aa46, - 0x303d49, - 0x37fc06, - 0x20ff4b, - 0x32a105, - 0x2a9506, - 0x2f8548, - 0x34df46, - 0x313ec6, - 0x216a4a, - 0x2d64ca, - 0x24fb45, - 0x307487, - 0x2fb286, - 0x61217042, - 0x2705c7, - 0x2ff1c5, - 0x2fbd04, - 0x2fbd05, - 0x220406, - 0x272087, - 0x21c385, - 0x25b644, - 0x2e0cc8, - 0x313f85, - 0x3c8647, - 0x3d43c5, - 0x210285, - 0x2c4e84, - 0x2e3cc9, - 0x2f8f88, - 0x238546, - 0x2e9c46, - 0x27d5c6, - 0x6170c3c8, - 0x30c5c7, - 0x30c90d, - 0x30cecc, - 0x30d4c9, - 0x30d709, - 0x61b75ac2, - 0x3d1b43, + 0x2f0806, + 0x20e486, + 0x24c845, + 0x2f7d48, + 0x26c544, + 0x26c546, + 0x256ccb, + 0x2b3449, + 0x235686, + 0x2e4009, + 0x20b1c6, + 0x345048, + 0x210543, + 0x30bd85, + 0x21a9c9, + 0x21c7c5, + 0x30e1c4, + 0x275d46, + 0x235a05, + 0x254306, + 0x319a07, + 0x247946, + 0x22c2cb, + 0x3c5987, + 0x3a28c6, + 0x2730c6, + 0x22d606, + 0x34c889, + 0x3b604a, + 0x2c58c5, + 0x3d6f8d, + 0x2abb46, + 0x23c346, + 0x2e6f86, + 0x21e5c5, + 0x2f1507, + 0x228ec7, + 0x27390e, + 0x23c803, + 0x2d5909, + 0x297289, + 0x22d287, + 0x26bbc7, + 0x2919c5, + 0x367b05, + 0x5f60210f, + 0x2db607, + 0x2db7c8, + 0x2dbb84, + 0x2dc046, + 0x5fa45402, + 0x2e01c6, + 0x2e2406, + 0x29744e, + 0x2e378a, + 0x207106, + 0x2b7c0a, + 0x3c7709, + 0x2fbe85, + 0x2ee188, + 0x3cbb46, + 0x2b7188, + 0x202ac8, + 0x277fcb, + 0x395f85, + 0x26f748, + 0x3dda4c, + 0x301207, + 0x24eb46, + 0x30c2c8, + 0x3de888, + 0x5fe30a42, + 0x21504b, + 0x205c89, + 0x28d989, + 0x21c647, + 0x3b5dc8, + 0x603d32c8, + 0x20934b, + 0x349bc9, + 0x25b18d, + 0x202908, + 0x2f1008, + 0x60604042, + 0x20d5c4, + 0x60a2aec2, + 0x3cd9c6, + 0x60e01282, + 0x2fbc8a, + 0x2a3806, + 0x34bd48, + 0x3c6908, + 0x3d9746, + 0x2ba946, + 0x3054c6, + 0x2ab045, + 0x239e44, + 0x6122ae04, + 0x359946, + 0x276247, + 0x6160d8c7, + 0x278b4b, + 0x295589, + 0x27bc0a, + 0x26d804, + 0x2f3b08, + 0x38e14d, + 0x2fc409, + 0x2fc648, + 0x2fc8c9, + 0x2fe7c4, + 0x2aae04, + 0x38d205, + 0x346f0b, + 0x36f606, + 0x359785, + 0x236209, + 0x31e6c8, + 0x22af84, + 0x327249, + 0x24a345, + 0x2dbdc8, + 0x2cd8c7, + 0x2889c8, + 0x281006, + 0x3ba447, + 0x2e6b09, + 0x3c9289, + 0x21d705, + 0x3682c5, + 0x61a1e342, + 0x31b244, + 0x21fe85, + 0x395d86, + 0x346905, + 0x244b07, + 0x359a45, + 0x276844, + 0x3487c6, + 0x254587, + 0x238f46, + 0x30a945, + 0x217108, + 0x35c7c5, + 0x21a847, + 0x2277c9, + 0x2b358a, + 0x264cc7, + 0x264ccc, + 0x265406, + 0x2423c9, + 0x31f045, + 0x369188, + 0x211ec3, + 0x398c45, + 0x3b9285, + 0x27b207, + 0x61e08dc2, + 0x2f8087, + 0x2eea86, + 0x38dc46, + 0x2f6146, + 0x3de7c6, + 0x230988, + 0x2d0145, + 0x31e1c7, + 0x31e1cd, + 0x210883, + 0x3d28c5, + 0x270007, + 0x2f83c8, + 0x26fbc5, + 0x214408, + 0x37cf06, + 0x2e50c7, + 0x2d4605, + 0x396006, + 0x393c45, + 0x20ba0a, + 0x310586, + 0x2645c7, + 0x2c9485, + 0x3a8a87, + 0x3cdb04, + 0x30e146, + 0x3cba85, + 0x39a18b, + 0x2f0689, + 0x27ef0a, + 0x21d788, + 0x314248, + 0x31968c, + 0x31adc7, + 0x330a08, + 0x335d88, + 0x3382c5, + 0x358dca, + 0x361049, + 0x62203242, + 0x2945c6, + 0x25c9c4, + 0x2fa949, + 0x35d749, + 0x2451c7, + 0x29b947, + 0x2bfb09, + 0x2ffe08, + 0x2ffe0f, + 0x21b5c6, + 0x2e4bcb, + 0x259dc5, + 0x259dc7, + 0x37bd49, + 0x20c8c6, + 0x3271c7, + 0x2e9105, + 0x230484, + 0x2f5006, + 0x220904, + 0x2f9c47, + 0x321c88, + 0x6270bb08, + 0x30c645, + 0x30c787, + 0x324389, + 0x20d184, + 0x241048, + 0x62bd0448, + 0x2e6f04, + 0x31d648, + 0x295a04, + 0x3b6349, + 0x21e505, + 0x62e33442, + 0x21b605, + 0x2dd945, + 0x289548, + 0x233a07, + 0x632008c2, + 0x22af45, + 0x2de0c6, + 0x243906, + 0x31b208, + 0x338fc8, + 0x3468c6, + 0x34afc6, + 0x306a09, + 0x38db86, + 0x20c78b, + 0x3c2705, + 0x2ac8c6, + 0x3c4a88, + 0x33f6c6, + 0x224786, + 0x216bca, + 0x2df94a, + 0x248a45, + 0x30ce07, + 0x274586, + 0x63603642, + 0x270147, + 0x33c305, + 0x304584, + 0x304585, + 0x2f3a06, + 0x272c47, + 0x203945, + 0x2dfac4, + 0x352248, + 0x224845, + 0x37ae87, + 0x3ca445, + 0x20b945, + 0x2d2904, + 0x2d2909, + 0x2ff2c8, + 0x23a5c6, + 0x35aa06, + 0x302d06, + 0x63bd5b08, + 0x311d07, + 0x31234d, + 0x312f0c, + 0x313509, + 0x313749, + 0x63f75442, + 0x3d4a03, 0x2010c3, - 0x2cff85, - 0x3a554a, - 0x33cdc6, - 0x23fd45, - 0x317944, - 0x31794b, - 0x33280c, - 0x33310c, - 0x333415, - 0x3342cd, - 0x336e4f, - 0x337212, - 0x33768f, - 0x337a52, - 0x337ed3, - 0x33838d, - 0x33894d, - 0x338cce, - 0x33924e, - 0x33994c, - 0x339d0c, - 0x33a14b, - 0x33abce, - 0x33b4d2, - 0x33cb8c, - 0x33d2d0, - 0x34fdd2, - 0x350c0c, - 0x3512cd, - 0x35160c, - 0x3536d1, + 0x2f08c5, + 0x3a784a, + 0x338e86, + 0x23cec5, + 0x31a504, + 0x31a50b, + 0x32d64c, + 0x32df0c, + 0x32e215, + 0x32f70d, + 0x33208f, + 0x332452, + 0x3328cf, + 0x332c92, + 0x333113, + 0x3335cd, + 0x333b8d, + 0x333f0e, + 0x33480e, + 0x334e0c, + 0x3351cc, + 0x33560b, + 0x33668e, + 0x336f92, + 0x338c4c, + 0x3391d0, + 0x34cfd2, + 0x34e08c, + 0x34e74d, + 0x34ea8c, + 0x351591, + 0x35280d, 0x3546cd, - 0x356f0d, - 0x35750a, - 0x35778c, - 0x358c4c, - 0x3591cc, - 0x359d4c, - 0x35d4d3, - 0x35db50, - 0x35df50, - 0x35e8cd, - 0x35eecc, - 0x35fc49, - 0x3618cd, - 0x361c13, - 0x363251, - 0x363a53, - 0x36474f, - 0x364b0c, - 0x364e0f, - 0x3651cd, - 0x3657cf, - 0x365b90, - 0x36660e, - 0x36b18e, - 0x36cad0, - 0x36da4d, - 0x36e3ce, - 0x36e74c, - 0x36fa13, - 0x37180e, - 0x371e90, - 0x372291, - 0x3726cf, - 0x372a93, - 0x37564d, - 0x37598f, - 0x375d4e, - 0x3762d0, - 0x3766c9, - 0x378490, - 0x378a8f, - 0x37910f, - 0x3794d2, - 0x379c8e, - 0x37a68d, - 0x37b00d, - 0x37b34d, - 0x37c70d, - 0x37ca4d, - 0x37cd90, - 0x37d18b, - 0x37d9cc, - 0x37dd4c, - 0x37e34c, - 0x37e64e, - 0x38c7d0, - 0x38e512, - 0x38e98b, - 0x38f4ce, - 0x38f84e, - 0x3900ce, - 0x39054b, - 0x61f909d6, - 0x3912cd, - 0x391754, - 0x39244d, - 0x393ad5, - 0x39578d, - 0x39610f, - 0x3968cf, - 0x39a50f, - 0x39a8ce, - 0x39ae4d, - 0x39ca11, - 0x39eb0c, - 0x39ee0c, - 0x39f10b, - 0x39f54c, - 0x39fbcf, - 0x39ff92, - 0x3a088d, - 0x3a198c, - 0x3a244c, - 0x3a274d, - 0x3a2a8f, - 0x3a2e4e, - 0x3a520c, - 0x3a57cd, - 0x3a5b0b, - 0x3a63cc, - 0x3a6ccd, - 0x3a700e, - 0x3a7389, - 0x3a83d3, - 0x3aa18d, - 0x3aa88d, - 0x3aae8c, - 0x3ab30e, - 0x3ac78f, - 0x3acb4c, - 0x3ace4d, - 0x3ad18f, - 0x3ad54c, - 0x3ae3cc, - 0x3ae88c, - 0x3aeb8c, - 0x3af24d, - 0x3af592, - 0x3b164c, - 0x3b194c, - 0x3b1c51, - 0x3b208f, - 0x3b244f, - 0x3b2813, - 0x3b374e, - 0x3b3acf, - 0x3b3e8c, - 0x623b41ce, - 0x3b454f, - 0x3b4916, - 0x3b5452, - 0x3b7d4c, - 0x3bb14f, - 0x3bb7cd, - 0x3c76cf, - 0x3c7a8c, - 0x3c7d8d, - 0x3c80cd, - 0x3c988e, - 0x3ca3cc, - 0x3cd64c, - 0x3cd950, - 0x3d0ed1, - 0x3d130b, - 0x3d174c, - 0x3d1a4e, - 0x3d4811, - 0x3d4c4e, - 0x3d4fcd, - 0x3d854b, - 0x3d8e4f, - 0x3d9814, - 0x220482, - 0x220482, - 0x227dc3, - 0x220482, - 0x227dc3, - 0x220482, - 0x204142, - 0x244285, - 0x3d450c, - 0x220482, - 0x220482, - 0x204142, - 0x220482, - 0x2974c5, - 0x2c6a45, - 0x220482, - 0x220482, - 0x208342, - 0x2974c5, - 0x334a89, - 0x362f4c, - 0x220482, - 0x220482, - 0x220482, - 0x220482, - 0x244285, - 0x220482, - 0x220482, - 0x220482, - 0x220482, - 0x208342, - 0x334a89, - 0x220482, - 0x220482, - 0x220482, - 0x2c6a45, - 0x220482, - 0x2c6a45, - 0x362f4c, - 0x3d450c, - 0x248343, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x224e44, - 0x20a803, - 0x216603, - 0x62f0f647, - 0x1ce4cf, - 0x144208, - 0x6704, - 0xca43, - 0xcd248, - 0x5bc4, + 0x354cca, + 0x354f4c, + 0x35890c, + 0x35948c, + 0x359e8c, + 0x35df93, + 0x35e710, + 0x35eb10, + 0x35f10d, + 0x35f70c, + 0x360549, + 0x36224d, + 0x362593, + 0x364111, + 0x364913, + 0x36560f, + 0x3659cc, + 0x365ccf, + 0x36608d, + 0x36668f, + 0x366a50, + 0x3674ce, + 0x36b40e, + 0x36ba90, + 0x36d08d, + 0x36da0e, + 0x36dd8c, + 0x36ed53, + 0x37268e, + 0x372c10, + 0x373011, + 0x37344f, + 0x373813, + 0x374fcd, + 0x37530f, + 0x3756ce, + 0x375c50, + 0x376049, + 0x3773d0, + 0x3778cf, + 0x377f4f, + 0x378312, + 0x3792ce, + 0x37a00d, + 0x37a54d, + 0x37a88d, + 0x37bf8d, + 0x37c2cd, + 0x37c610, + 0x37ca0b, + 0x37d24c, + 0x37d5cc, + 0x37dbcc, + 0x37dece, + 0x38d350, + 0x38f7d2, + 0x38fc4b, + 0x39078e, + 0x390b0e, + 0x39138e, + 0x39190b, + 0x64391d96, + 0x39268d, + 0x393214, + 0x393f0d, + 0x3955d5, + 0x3978cd, + 0x39824f, + 0x398e0f, + 0x39c24f, + 0x39c60e, + 0x39c98d, + 0x39e251, + 0x3a084c, + 0x3a0b4c, + 0x3a0e4b, + 0x3a128c, + 0x3a1ccf, + 0x3a2092, + 0x3a2bcd, + 0x3a470c, + 0x3a500c, + 0x3a530d, + 0x3a564f, + 0x3a5a0e, + 0x3a750c, + 0x3a7acd, + 0x3a7e0b, + 0x3a8c4c, + 0x3a954d, + 0x3a988e, + 0x3a9c09, + 0x3abb53, + 0x3ac94d, + 0x3ad04d, + 0x3ad64c, + 0x3ae88e, + 0x3aef8f, + 0x3af34c, + 0x3af64d, + 0x3af98f, + 0x3afd4c, + 0x3b034c, + 0x3b080c, + 0x3b0b0c, + 0x3b35cd, + 0x3b3912, + 0x3b45cc, + 0x3b48cc, + 0x3b4bd1, + 0x3b500f, + 0x3b53cf, + 0x3b5793, + 0x3b6f8e, + 0x3b730f, + 0x3b76cc, + 0x647b7d8e, + 0x3b810f, + 0x3b84d6, + 0x3bae52, + 0x3bcccc, + 0x3bdb8f, + 0x3be20d, + 0x3c94cf, + 0x3c988c, + 0x3c9b8d, + 0x3c9ecd, + 0x3cb4ce, + 0x3cc38c, + 0x3ceecc, + 0x3cf1d0, + 0x3d3d91, + 0x3d41cb, + 0x3d460c, + 0x3d490e, + 0x3d6011, + 0x3d644e, + 0x3d67cd, + 0x3dbc0b, + 0x3dc88f, + 0x3dd454, + 0x23c782, + 0x23c782, + 0x23e083, + 0x23c782, + 0x23e083, + 0x23c782, + 0x203802, + 0x246c45, + 0x3d5d0c, + 0x23c782, + 0x23c782, + 0x203802, + 0x23c782, + 0x29b485, + 0x2b3585, + 0x23c782, + 0x23c782, + 0x201542, + 0x29b485, + 0x32fec9, + 0x363e0c, + 0x23c782, + 0x23c782, + 0x23c782, + 0x23c782, + 0x246c45, + 0x23c782, + 0x23c782, + 0x23c782, + 0x23c782, + 0x201542, + 0x32fec9, + 0x23c782, + 0x23c782, + 0x23c782, + 0x2b3585, + 0x23c782, + 0x2b3585, + 0x363e0c, + 0x3d5d0c, + 0x202703, + 0x214a83, + 0x232dc3, + 0x308003, + 0x221dc4, + 0x21a3c3, + 0x242543, + 0x1d904f, + 0x145988, + 0x1a704, + 0x3dc3, + 0x86808, + 0x1cc203, 0x2000c2, - 0x6360c302, - 0x23e483, - 0x259844, - 0x2020c3, - 0x2d3b84, - 0x22f446, - 0x20b8c3, - 0x30b0c4, - 0x398685, - 0x211543, - 0x20a803, - 0x6d9c3, - 0x216603, - 0x21de8a, - 0x253c46, - 0x38fbcc, - 0x9fe08, - 0x20c302, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x238cc3, - 0x2d9bc6, - 0x20a803, - 0x216603, - 0x216103, - 0x2f783, - 0xa9148, - 0x641c6005, - 0x453c7, - 0x12eb85, - 0x9349, - 0xc6c2, - 0x1b5fca, - 0x64f9e785, - 0x12eb85, - 0x6bb47, - 0x6d448, - 0x680e, - 0x894d2, - 0x173e0b, - 0x10f186, - 0x6528b745, - 0x6568b74c, - 0x8ec47, - 0x176c87, - 0x12650a, - 0x3a210, - 0xe7945, - 0x10a7cb, - 0x18a0c8, - 0x67607, - 0x11404b, - 0x330c9, - 0x44447, - 0x16c307, - 0x77507, - 0x346c6, - 0xe688, - 0x65c39346, - 0x45887, - 0x147786, - 0x189d4d, - 0xc78d0, - 0x66009802, - 0x114c8, - 0x67fd0, - 0x181a8c, - 0x6678b84d, - 0x59648, - 0x59acb, - 0x68e47, - 0x6e149, - 0x54c46, - 0x97048, - 0x33c2, - 0x198c0a, - 0x1cb807, - 0x35147, - 0xaa289, - 0xac0c8, - 0x20005, - 0x18ce06, - 0x1ba306, - 0x100d4e, - 0x240ce, - 0x14f5cf, - 0xe3389, - 0x6dc89, - 0x19878b, - 0xa318f, - 0x15090c, - 0xc010b, - 0xd8fc8, - 0x116e87, - 0x15f548, - 0x18e14b, - 0x194fcc, - 0x19bd8c, - 0x19f8cc, - 0xb08cd, - 0x1432c8, - 0xf10c2, - 0x191f89, - 0x45c88, - 0x19e10b, - 0xcb446, - 0xd408b, - 0x13b00b, - 0xdf54a, - 0xe1145, - 0xe9250, - 0xeba46, - 0x52286, - 0x175305, - 0x114587, - 0xd6fc8, - 0xef9c7, - 0xefc87, - 0x184907, - 0xc10c6, - 0x1ab8ca, - 0x9fc8a, - 0x13686, - 0xad44d, - 0x45948, - 0x111788, - 0x112009, - 0xb9545, - 0x1a214c, - 0xb0acb, - 0x1cab84, - 0x10c009, - 0x10c246, - 0x4a506, - 0x1bff46, - 0x5402, - 0x3e006, - 0xbe70b, - 0x118547, - 0x57c2, - 0xccc85, - 0x63444, + 0x65601242, + 0x240983, + 0x224c84, + 0x207083, + 0x384584, + 0x22f7c6, + 0x310c83, + 0x310c44, + 0x2f0b05, + 0x23c803, + 0x21a3c3, + 0x1b4103, + 0x242543, + 0x21e2ca, + 0x252b06, + 0x390e8c, + 0x9a048, + 0x201242, + 0x214a83, + 0x232dc3, + 0x308003, + 0x2137c3, + 0x2e2406, + 0x21a3c3, + 0x242543, + 0x2141c3, + 0x2fb03, + 0xac508, + 0x661d2145, + 0x47d47, + 0x139b05, + 0x156c9, + 0x1742, + 0x13a14a, + 0x66fa0505, + 0x139b05, + 0x29907, + 0x6dfc8, + 0x9c4e, + 0x8b392, + 0x9630b, + 0x10d806, + 0x6728d505, + 0x6768d50c, + 0x13d547, + 0x17e707, + 0x12364a, + 0x3be50, + 0x146145, + 0x10fe4b, + 0x79108, + 0x25687, + 0x2490b, + 0x33249, + 0x46e07, + 0x15c087, + 0xc2487, + 0x34a06, + 0x106c8, + 0x67c28886, + 0x47207, + 0x18ec46, + 0x78d8d, + 0xf3c90, + 0x680aac82, + 0xd1288, + 0x40350, + 0x17f5cc, + 0x687825cd, + 0x5a988, + 0x5ae0b, + 0x6b187, + 0x70749, + 0x56306, + 0x9b008, + 0x3ee42, + 0x9218a, + 0x157647, + 0x107c07, + 0xacdc9, + 0xaff88, + 0xf3605, + 0x18d986, + 0x1ba1c6, + 0xfd84e, + 0xaf88e, + 0x3874f, + 0x41a89, + 0xf0c09, + 0x91d0b, + 0xb3b4f, + 0xbd08c, + 0xca18b, + 0x131388, + 0x171887, + 0x197088, + 0xb580b, + 0xb5bcc, + 0xb5fcc, + 0xb63cc, + 0xb66cd, + 0x1b1148, + 0x52e82, + 0x193a49, + 0x112988, + 0x19fe8b, + 0xd5b46, + 0xdda8b, + 0x136acb, + 0xe884a, + 0xea585, + 0xf1210, + 0xf5c86, + 0x184806, + 0x97805, + 0x91487, + 0xe0448, + 0xf92c7, + 0xf9587, + 0x12c807, + 0xc7346, + 0x1cd80a, + 0x99eca, + 0x11ec6, + 0xb130d, + 0x472c8, + 0x115488, + 0x115cc9, + 0xc0545, + 0x1aec8c, + 0xb68cb, + 0x86fc9, + 0x1ccb44, + 0x111949, + 0x111b86, + 0x4cec6, + 0x3c686, + 0x1b82, + 0x365c6, + 0x13dacb, + 0x129187, + 0x11ac47, + 0x1442, + 0xd7445, + 0x27e04, 0x101, - 0x50343, - 0x65a669c6, - 0x973c3, + 0x4fd83, + 0x67a37806, + 0x9b383, 0x382, - 0x2b704, + 0x26bc4, 0xac2, - 0x42244, + 0xd3684, 0x882, - 0x4c82, - 0x19c2, - 0x27682, - 0x4042, - 0x8b742, + 0x31c2, + 0x16c2, + 0x20f82, + 0x86c2, + 0x8d502, 0xd42, - 0x8cac2, - 0x36182, - 0x59dc2, - 0x81c2, - 0x4cfc2, - 0x32c43, + 0x167c2, + 0x373c2, + 0x5582, + 0x2a42, + 0x4e782, + 0x32dc3, 0x942, - 0x1bc2, - 0xc202, - 0x3d42, + 0x3c42, + 0xdec2, + 0x5dc2, 0x642, - 0x30ac2, - 0x4742, - 0x1cc2, + 0x315c2, + 0x6502, + 0x5bc2, 0xf42, 0x5c2, - 0x14543, - 0x1742, - 0x2cc2, - 0x48902, - 0x4e082, - 0x3102, - 0x5f82, - 0x17002, - 0x1fc02, - 0x6a42, - 0x140d82, - 0x6bf42, - 0x9082, - 0xa803, + 0x1bc83, + 0x4582, + 0x7882, + 0x49582, + 0x1e42, + 0x2042, + 0x8282, + 0x23502, + 0x17c2, + 0x9e82, + 0x3f82, + 0x6c9c2, + 0x15402, + 0x1a3c3, 0x602, - 0x39242, - 0x2f42, - 0x23242, - 0x137c5, - 0x8242, - 0x20082, - 0x3b1c3, + 0x30a42, + 0x2902, + 0x1ad42, + 0x1d685, + 0xa882, + 0x14b42, + 0x3d383, 0x682, - 0xa982, - 0x2e42, - 0x1702, - 0x1782, + 0xca42, + 0x45c2, + 0x7842, + 0x2f82, 0x8c2, - 0x14302, - 0x5402, - 0x7d45, - 0x66a04142, - 0x66f6d603, - 0x13583, - 0x67204142, - 0x13583, - 0x819c7, - 0x209e83, + 0xc2c2, + 0x1b82, + 0x1805, + 0x68a03802, + 0x68edf283, + 0xf283, + 0x69203802, + 0xf283, + 0x74c47, + 0x201503, 0x2000c2, - 0x22c0c3, - 0x232c43, - 0x212483, + 0x214a83, + 0x232dc3, + 0x228503, 0x2005c3, - 0x238cc3, - 0x20a803, - 0x20ca43, - 0x216603, - 0x297403, - 0xfba85, - 0x8303, - 0x9fe08, - 0x22c0c3, - 0x232c43, - 0x212483, - 0x211543, - 0x20a803, - 0x20ca43, - 0x6d9c3, - 0x216603, - 0x22c0c3, - 0x232c43, - 0x216603, - 0x22c0c3, - 0x232c43, - 0x228b03, + 0x2137c3, + 0x21a3c3, + 0x203dc3, + 0x242543, + 0x29b3c3, + 0xc0584, + 0x19405, + 0x104305, + 0x3a83, + 0x9a048, + 0x214a83, + 0x232dc3, + 0x228503, + 0x23c803, + 0x21a3c3, + 0x203dc3, + 0x1b4103, + 0x242543, + 0x214a83, + 0x232dc3, + 0x242543, + 0x214a83, + 0x232dc3, + 0x308003, 0x200181, - 0x211543, - 0x20a803, - 0x24bbc3, - 0x216603, - 0xbef44, - 0x248343, - 0x22c0c3, - 0x232c43, - 0x20d083, - 0x212483, - 0x35c6c3, - 0x2042c3, - 0x2a6b43, - 0x20edc3, - 0x228b03, - 0x224e44, - 0x20a803, - 0x216603, - 0x205b03, - 0x345344, - 0x25cc83, - 0x25843, - 0x2287c3, - 0x32b808, - 0x27d8c4, + 0x23c803, + 0x21a3c3, + 0x24e283, + 0x242543, + 0x69944, + 0x202703, + 0x214a83, + 0x232dc3, + 0x218bc3, + 0x228503, + 0x2c26c3, + 0x208943, + 0x2a37c3, + 0x216243, + 0x308003, + 0x221dc4, + 0x21a3c3, + 0x242543, + 0x207783, + 0x204244, + 0x24f603, + 0x20dc3, + 0x29cfc3, + 0x328fc8, + 0x2f0e44, 0x20020a, - 0x31fa06, - 0x124804, - 0x38ad87, - 0x22090a, - 0x223989, - 0x3b2c87, - 0x3b588a, - 0x248343, - 0x3ac10b, - 0x3c28c9, - 0x2d3185, - 0x3ae6c7, - 0xc302, - 0x22c0c3, - 0x3c3187, - 0x26a3c5, - 0x2c7249, - 0x232c43, - 0x2bd546, - 0x2c5d83, - 0xcfe03, - 0x115f06, - 0x13f146, - 0xb847, - 0x21e686, - 0x2276c5, - 0x3de0c7, - 0x312847, - 0x69e28b03, - 0x350e47, - 0x3c0043, - 0x20a405, - 0x224e44, - 0x26f848, - 0x37a38c, - 0x2b2045, - 0x2a6746, - 0x3c3047, - 0x3a9ac7, - 0x243a87, - 0x24fc48, - 0x314f4f, - 0x223bc5, - 0x23e587, - 0x205147, - 0x2a850a, - 0x2ec6c9, - 0x31e445, - 0x320fca, - 0xbc7c6, - 0xb9a07, - 0x2c5e05, - 0x2ed104, - 0x3c0146, - 0xdd246, - 0x381d07, - 0x2f0fc7, - 0x369748, - 0x2188c5, - 0x26a2c6, - 0x25788, - 0x2eaf85, - 0xeb146, - 0x2311c5, - 0x28b084, - 0x306907, - 0x238fca, - 0x336408, - 0x36a346, - 0x38cc3, - 0x2e2a45, - 0x322406, - 0x3b5186, - 0x375206, - 0x211543, - 0x3a0b07, - 0x2050c5, - 0x20a803, - 0x2df80d, - 0x20ca43, - 0x369848, - 0x20fcc4, - 0x276f45, - 0x2a8406, - 0x394306, - 0x2a9407, - 0x259d07, - 0x28aa85, - 0x216603, - 0x31a207, - 0x316f89, - 0x26e2c9, - 0x2524ca, - 0x2091c2, - 0x20a3c4, - 0x302604, - 0x2ee247, - 0x2ee648, - 0x2f0889, - 0x3c6649, - 0x2f1507, - 0x101f49, - 0x21ee46, - 0xf4a86, - 0x2f61c4, - 0x22c50a, - 0x2fab08, - 0x2fc809, - 0x2fcdc6, - 0x2b6305, - 0x3362c8, - 0x2cb88a, - 0x24f1c3, - 0x3454c6, - 0x2f1607, - 0x31f785, - 0x3a4245, - 0x240a83, - 0x246484, - 0x228305, - 0x285dc7, - 0x2f90c5, - 0x2f6a46, - 0x11ba45, - 0x359a43, - 0x3d26c9, - 0x276d0c, - 0x2bb5cc, - 0x39e908, - 0x2a98c7, - 0x3085c8, - 0x108c07, - 0x30944a, - 0x309b0b, - 0x3c2a08, - 0x394408, - 0x3db806, - 0x27d485, - 0x33954a, - 0x36d645, - 0x219f82, - 0x2c9ac7, - 0x24d686, - 0x377b45, - 0x30adc9, - 0x27ae85, - 0x295b05, - 0x2f8249, - 0x322346, - 0x329788, - 0x267dc3, - 0x21e7c6, - 0x275506, - 0x318085, - 0x318089, - 0x2bc409, - 0x27d207, - 0x11abc4, - 0x31abc7, - 0x3c6549, - 0x220b05, - 0x37ec8, - 0x342dc5, - 0x28e1c5, - 0x383dc9, - 0x202542, - 0x3d2c04, - 0x201e82, - 0x201742, - 0x2e5285, - 0x324588, - 0x2b9485, - 0x2c8c83, - 0x2c8c85, - 0x2d6f43, - 0x2071c2, - 0x331d04, - 0x26e683, + 0x235406, + 0x124184, + 0x3a71c7, + 0x21ec8a, + 0x21b489, + 0x3bb287, + 0x3c024a, + 0x202703, + 0x35604b, + 0x216189, + 0x2f4245, + 0x3b0647, + 0x1242, + 0x214a83, + 0x20fcc7, + 0x263bc5, + 0x2cc8c9, + 0x232dc3, + 0x373ec6, + 0x2cb983, + 0xeeb03, + 0x118f86, + 0x98186, + 0x1d3bc7, + 0x212286, + 0x220fc5, + 0x205b47, + 0x316507, + 0x6bf08003, + 0x34e2c7, + 0x23c783, + 0x3d3905, + 0x221dc4, + 0x26f3c8, + 0x385acc, + 0x2b8d05, + 0x2aa446, + 0x20fb87, + 0x3b9887, + 0x3a2a07, + 0x248b48, + 0x317ccf, + 0x21b6c5, + 0x240a87, + 0x28e747, + 0x276e0a, + 0x37b549, + 0x3dd185, + 0x3212ca, + 0xc4ac6, + 0xc0a07, + 0x2cba05, + 0x2f6684, + 0x3d9686, + 0x101406, + 0x37f847, + 0x252d87, + 0x33b388, + 0x218405, + 0x263ac6, + 0x156ec8, + 0x2e3d85, + 0xe3f46, + 0x3268c5, + 0x28ce44, + 0x24a407, + 0x2307ca, + 0x23ab88, + 0x288e06, + 0x137c3, + 0x2ec0c5, + 0x320506, + 0x3bee46, + 0x297706, + 0x23c803, + 0x3a2e47, + 0x28e6c5, + 0x21a3c3, + 0x2e8b0d, + 0x203dc3, + 0x33b488, + 0x213484, + 0x276b05, + 0x2abd06, + 0x205406, + 0x2ac7c7, + 0x25b047, + 0x350ac5, + 0x242543, + 0x271d87, + 0x371989, + 0x2708c9, + 0x384a4a, + 0x215542, + 0x3d38c4, + 0x2fb304, + 0x2f7c07, + 0x2f7f48, + 0x2fa3c9, + 0x3d2789, + 0x2fadc7, + 0x109049, + 0x362f06, + 0xfd5c6, + 0x2fe7c4, + 0x22cf8a, + 0x302448, + 0x305389, + 0x305946, + 0x2bc745, + 0x23aa48, + 0x2d5dca, + 0x32bf03, + 0x2043c6, + 0x2faec7, + 0x35a785, + 0x3b4045, + 0x2432c3, + 0x23e804, + 0x227b45, + 0x2848c7, + 0x2ff405, + 0x2ff846, + 0x111e85, + 0x2071c3, + 0x2071c9, + 0x2768cc, + 0x2c61cc, + 0x3444c8, + 0x2ab3c7, + 0x30d588, + 0x10e747, + 0x30eaca, + 0x30f18b, + 0x2162c8, + 0x205508, + 0x22b686, + 0x302bc5, + 0x25d70a, + 0x2df2c5, + 0x233442, + 0x2d44c7, + 0x253c46, + 0x376785, + 0x310949, + 0x2d0405, + 0x372185, + 0x3c2409, + 0x320446, + 0x201348, + 0x3d39c3, + 0x20aa46, + 0x275c86, + 0x31cd05, + 0x31cd09, + 0x2c4709, + 0x25d487, + 0x11cb84, + 0x31cb87, + 0x3d2689, + 0x21ee85, + 0x39f48, + 0x349845, + 0x353885, + 0x39b489, + 0x204b42, + 0x357204, + 0x209282, + 0x204582, + 0x2ed985, + 0x323f08, + 0x2c0485, + 0x2ced43, + 0x2ced45, + 0x2e03c3, + 0x20a742, + 0x2b4384, + 0x269f03, 0x200a82, - 0x3b8944, - 0x311943, - 0x212842, - 0x2b9503, - 0x213604, - 0x2fcf43, - 0x254ec4, - 0x204e82, - 0x216003, - 0x219c83, - 0x202602, - 0x293042, - 0x2bc249, - 0x20fa02, - 0x28a304, - 0x20d542, - 0x336144, - 0x21ee04, - 0x252b44, - 0x205402, - 0x23b4c2, - 0x387e43, - 0x298cc3, - 0x2614c4, - 0x28dcc4, - 0x2d0984, - 0x2f1784, - 0x31ad43, - 0x300b03, - 0x2bc744, - 0x31d9c4, - 0x31db06, - 0x20b582, - 0xc302, - 0x3ef83, - 0x20c302, - 0x232c43, - 0x228b03, - 0x20a803, - 0x216603, + 0x3b17c4, + 0x309703, + 0x20cb42, + 0x2c0503, + 0x211e44, + 0x305ac3, + 0x255544, + 0x205142, + 0x2140c3, + 0x21ab03, + 0x2071c2, + 0x294ec2, + 0x2c4549, + 0x205b02, + 0x28bec4, + 0x206542, + 0x23a8c4, + 0x362ec4, + 0x3b4384, + 0x201b82, + 0x22b2c2, + 0x22db03, + 0x29cec3, + 0x3269c4, + 0x3aa684, + 0x2dae84, + 0x2ea884, + 0x31bcc3, + 0x312743, + 0x2c4a44, + 0x31f184, + 0x31f2c6, + 0x21d642, + 0x1242, + 0x41483, + 0x201242, + 0x232dc3, + 0x308003, + 0x21a3c3, + 0x242543, + 0x6c05, 0x2000c2, - 0x248343, - 0x22c0c3, - 0x232c43, - 0x205e03, - 0x228b03, - 0x224e44, - 0x2bc504, - 0x217b84, - 0x20a803, - 0x216603, - 0x216103, - 0x2f8a84, - 0x32ce03, - 0x2aad03, - 0x37a944, - 0x342bc6, - 0x20e5c3, - 0x12eb85, - 0x176c87, - 0x2e4003, - 0x6b644548, - 0x2420c3, - 0x2b4103, - 0x20a443, - 0x238cc3, - 0x3afd05, - 0x1ae683, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x20a803, - 0x216603, - 0x208243, - 0x22dcc3, - 0x9fe08, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x214543, - 0x20a803, - 0x27f984, - 0x6d9c3, - 0x216603, - 0x2ba0c4, - 0x12eb85, - 0x2c2ac5, - 0x176c87, - 0x20c302, - 0x201d02, + 0x202703, + 0x214a83, + 0x232dc3, + 0x209b03, + 0x308003, + 0x221dc4, + 0x2c4804, + 0x219a04, + 0x21a3c3, + 0x242543, + 0x2141c3, + 0x2fedc4, + 0x297a83, + 0x2ad843, + 0x37a2c4, + 0x349646, + 0x210603, + 0x139b05, + 0x17e707, + 0x2d2c43, + 0x6da46f08, + 0x2532c3, + 0x2bb143, + 0x25cc03, + 0x2137c3, + 0x3c0ac5, + 0x1b0603, + 0x214a83, + 0x232dc3, + 0x308003, + 0x21a3c3, + 0x242543, + 0x20a883, + 0x22ee03, + 0x9a048, + 0x214a83, + 0x232dc3, + 0x308003, + 0x21bc83, + 0x21a3c3, + 0x2801c4, + 0x1b4103, + 0x242543, + 0x24a004, + 0x139b05, + 0x2c8f85, + 0x17e707, + 0x201242, + 0x2052c2, 0x200382, - 0x205642, - 0xca43, + 0x208482, + 0x3dc3, 0x2003c2, - 0x1244, - 0x22c0c3, - 0x235604, - 0x232c43, - 0x228b03, - 0x211543, - 0x20a803, - 0x216603, - 0x9fe08, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x211543, - 0x217b84, - 0x20a803, - 0xca43, - 0x216603, - 0x20c603, - 0x242244, - 0x9fe08, - 0x22c0c3, - 0x20ca43, - 0x8303, - 0x123ec4, - 0x249f84, - 0x9fe08, - 0x22c0c3, - 0x24b304, - 0x224e44, - 0x20ca43, - 0x201e02, - 0x6d9c3, - 0x216603, - 0x236bc3, - 0x46484, - 0x204185, - 0x219f82, - 0x2be683, - 0x2b49, - 0xddb86, - 0x142ec8, + 0x4f04, + 0x214a83, + 0x235b44, + 0x232dc3, + 0x308003, + 0x23c803, + 0x21a3c3, + 0x242543, + 0x9a048, + 0x214a83, + 0x232dc3, + 0x308003, + 0x23c803, + 0x219a04, + 0x21a3c3, + 0x3dc3, + 0x242543, + 0x20e2c3, + 0x2d3684, + 0x9a048, + 0x214a83, + 0x203dc3, + 0x3a83, + 0x122504, + 0x24c0c4, + 0x9a048, + 0x214a83, + 0x24d9c4, + 0x221dc4, + 0x203dc3, + 0x204042, + 0x1b4103, + 0x242543, + 0x22b983, + 0x3e804, + 0x208805, + 0x233442, + 0x325e43, + 0x68b49, + 0xe5986, + 0x149948, 0x2000c2, - 0x9fe08, - 0x20c302, - 0x232c43, - 0x228b03, + 0x9a048, + 0x201242, + 0x232dc3, + 0x308003, 0x2005c2, - 0xca43, - 0x216603, - 0x5942, + 0x3dc3, + 0x242543, + 0x7c42, 0x82, 0xc2, - 0x1b5a47, - 0x13dc09, - 0x7be83, - 0x9fe08, - 0x27643, - 0x6ef26287, - 0x2c0c3, - 0x6048, - 0x32c43, - 0x28b03, - 0x3a086, - 0x14543, - 0x96448, - 0xc53c8, - 0x79046, - 0x11543, - 0xce788, - 0xb7e03, - 0x6f0e23c6, - 0xea185, - 0x32e47, - 0xa803, - 0x21803, - 0x16603, - 0xb142, - 0x17d48a, - 0x4e03, - 0xe5343, - 0xfe804, - 0x114d4b, - 0x115308, - 0x91482, - 0x1451207, - 0x153efc7, - 0x14c8d48, - 0x151d403, - 0x10044b, - 0x8582, - 0x12ea07, - 0x10cbc4, + 0x1c0407, + 0x142c09, + 0x7aec3, + 0x9a048, + 0x20f43, + 0x713233c7, + 0x14a83, + 0x944c8, + 0x32dc3, + 0x108003, + 0x1ab9c6, + 0x1bc83, + 0x92788, + 0xcae48, + 0xcff06, + 0x3c803, + 0xd8cc8, + 0x44b83, + 0x714eb886, + 0xf1c05, + 0x32fc7, + 0x1a3c3, + 0x11003, + 0x42543, + 0xeb02, + 0x17cd0a, + 0x2cc3, + 0xeda43, + 0x10a104, + 0x117acb, + 0x118088, + 0x90602, + 0x14540c7, + 0x15636c7, + 0x14cee08, + 0x14cf583, + 0x143acb, + 0xb342, + 0x12bcc7, + 0x11b504, 0x2000c2, - 0x20c302, - 0x235604, - 0x228b03, - 0x211543, - 0x20a803, - 0x216603, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x238cc3, - 0x20a803, - 0x216603, - 0x2ba0c3, - 0x20c603, - 0x2f783, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x20a803, - 0x216603, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x20a803, - 0x216603, + 0x201242, + 0x235b44, + 0x308003, + 0x23c803, + 0x21a3c3, + 0x242543, + 0x214a83, + 0x232dc3, + 0x308003, + 0x2137c3, + 0x21a3c3, + 0x242543, + 0x215d43, + 0x20e2c3, + 0x2fb03, + 0x214a83, + 0x232dc3, + 0x308003, + 0x21a3c3, + 0x242543, + 0x214a83, + 0x232dc3, + 0x308003, + 0x21a3c3, + 0x242543, 0x602, - 0x8303, - 0x28b03, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x224e44, - 0x238cc3, - 0x20a803, - 0x216603, - 0x20ff42, + 0x3a83, + 0x108003, + 0x214a83, + 0x232dc3, + 0x308003, + 0x221dc4, + 0x2137c3, + 0x21a3c3, + 0x242543, + 0x20c782, 0x2000c1, 0x2000c2, 0x200201, - 0x336f42, - 0x9fe08, - 0x21c105, + 0x332182, + 0x9a048, + 0x21ca05, 0x200101, - 0x2c0c3, - 0x2fd84, - 0x2015c1, + 0x14a83, + 0x2fe44, + 0x201301, 0x200501, - 0x2014c1, - 0x244202, - 0x3874c4, - 0x244203, + 0x205dc1, + 0x246bc2, + 0x387fc4, + 0x246bc3, 0x200041, 0x200801, 0x200181, 0x200701, - 0x2f6b87, - 0x380f4f, - 0x3cac46, + 0x302fc7, + 0x30e38f, + 0x3ccc06, 0x2004c1, - 0x323f06, + 0x322546, 0x200bc1, 0x200581, - 0x3d878e, + 0x3affce, 0x2003c1, - 0x216603, + 0x242543, 0x200a81, - 0x2e3285, - 0x20b142, - 0x240985, + 0x34c105, + 0x20eb02, + 0x2431c5, 0x200401, 0x200741, 0x2007c1, - 0x219f82, + 0x233442, 0x200081, - 0x205841, - 0x201241, - 0x2018c1, - 0x204981, - 0x4e9c9, - 0x9fe08, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x20a803, - 0x216603, - 0x216e03, - 0x22c0c3, - 0x228b03, - 0x913c8, - 0x211543, - 0x20a803, - 0x70e03, - 0x216603, - 0x14ecd48, - 0x8148, - 0x12eb85, - 0x9fe08, - 0xca43, - 0x12eb85, - 0x1da144, - 0x116c8, - 0x42744, - 0xc9345, - 0x4e9c9, - 0x14ecd4a, - 0x9fe08, - 0x6d9c3, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x20a803, - 0x216603, - 0x225843, - 0x9fe08, - 0x22c0c3, - 0x232c43, - 0x2db1c4, - 0x216603, - 0x25cf45, - 0x27ac84, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x206a42, - 0x20a803, - 0x216603, - 0xc603, - 0xa924a, - 0x119b84, - 0x121d46, - 0x248343, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x20a803, - 0x216603, - 0x20c302, - 0x22c0c3, - 0x230309, - 0x232c43, - 0x2ac809, - 0x228b03, - 0x211543, - 0x20a803, - 0x189a44, - 0xca43, - 0x216603, - 0x2f5fc8, - 0x23ad87, - 0x204185, - 0x1d1548, - 0x1b5a47, - 0xee8ca, - 0x6fe0b, - 0x124147, - 0x3cd48, - 0x1198a, - 0x1a348, - 0x13dc09, - 0x281c7, - 0x106707, - 0x140cc8, - 0x6048, - 0x3e84f, - 0x17c45, - 0x16687, - 0x3a086, - 0x3fc07, - 0x11e586, - 0x96448, - 0x9f546, - 0x129587, - 0x143489, - 0x1a4ec7, - 0x9be49, - 0xba9c9, - 0xc2846, - 0xc53c8, - 0xc3a05, - 0x7c70a, - 0xce788, - 0xb7e03, - 0xd7348, - 0x32e47, - 0x13e8c5, - 0x64910, - 0x21803, - 0x6d9c3, - 0x129407, - 0x231c5, - 0xeff88, - 0x65305, - 0xe5343, - 0x3308, - 0xb446, - 0x92289, - 0xaebc7, - 0x2e0b, - 0x6c1c4, - 0x10b8c4, - 0x114d4b, - 0x115308, - 0x115e07, - 0x12eb85, - 0x22c0c3, - 0x232c43, - 0x212483, - 0x216603, - 0x23bf03, - 0x228b03, - 0x6d9c3, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x211543, - 0x20a803, - 0x216603, - 0x1988cb, + 0x201341, + 0x204f01, + 0x201b41, + 0x201441, + 0x50849, + 0x9a048, + 0x214a83, + 0x232dc3, + 0x308003, + 0x21a3c3, + 0x242543, + 0x214903, + 0x214a83, + 0x308003, + 0x90548, + 0x23c803, + 0x21a3c3, + 0x7283, + 0x242543, + 0x14f62c8, + 0x1e0603, + 0xa788, + 0x139b05, + 0x9a048, + 0x3dc3, + 0x139b05, + 0xcd184, + 0xd1488, + 0x455c4, + 0xcf487, + 0xd3b05, + 0x50849, + 0x11d287, + 0x14f62ca, + 0x9a048, + 0x1b4103, + 0x214a83, + 0x232dc3, + 0x308003, + 0x21a3c3, + 0x242543, + 0x220dc3, + 0x9a048, + 0x214a83, + 0x232dc3, + 0x2e3504, + 0x242543, + 0x24f8c5, + 0x2d0204, + 0x214a83, + 0x232dc3, + 0x308003, + 0x209e82, + 0x21a3c3, + 0x242543, + 0xe2c3, + 0xac60a, + 0xe8006, + 0x102804, + 0x122046, + 0x202703, + 0x214a83, + 0x232dc3, + 0x308003, + 0x21a3c3, + 0x242543, + 0x201242, + 0x214a83, + 0x2303c9, + 0x232dc3, + 0x2aa909, + 0x308003, + 0x23c803, + 0x21a3c3, + 0x78a84, + 0x3dc3, + 0x242543, + 0x2fe5c8, + 0x23c207, + 0x208805, + 0xdbc48, + 0x1d4408, + 0x1c0407, + 0xf81ca, + 0x6f98b, + 0x122787, + 0x3f888, + 0xd174a, + 0xf648, + 0x142c09, + 0x27a07, + 0x1fa87, + 0x3ec8, + 0x944c8, + 0x40d4f, + 0x3ad45, + 0x947c7, + 0x1ab9c6, + 0x3cd87, + 0x1dd2c6, + 0x92788, + 0x99786, + 0x1147, + 0x2fc9, + 0x18ab07, + 0x179dc9, + 0xc2749, + 0xc8d06, + 0xcae48, + 0xdbf05, + 0x7b74a, + 0xd8cc8, + 0x44b83, + 0xe07c8, + 0x32fc7, + 0x95d05, + 0x51590, + 0x11003, + 0x1b4103, + 0x2e47, + 0x1acc5, + 0xf9888, + 0x66605, + 0xeda43, + 0x1cb7c8, + 0xee06, + 0x32109, + 0xb2b87, + 0x68e0b, + 0x6cc44, + 0x111444, + 0x117acb, + 0x118088, + 0x118e87, + 0x139b05, + 0x214a83, + 0x232dc3, + 0x228503, + 0x242543, + 0x23e343, + 0x308003, + 0x1b4103, + 0x214a83, + 0x232dc3, + 0x308003, + 0x23c803, + 0x21a3c3, + 0x242543, + 0x91e4b, 0x2000c2, - 0x20c302, - 0x216603, - 0x9fe08, - 0x133d89, - 0xc302, + 0x201242, + 0x242543, + 0xd42, + 0x9e82, + 0x7782, + 0x9a048, + 0x1b3089, + 0x1242, 0x2000c2, - 0x20c302, + 0x201242, 0x200382, 0x2005c2, - 0x206702, - 0x20a803, - 0x133a46, + 0x210942, + 0x21a3c3, + 0x13f246, 0x2003c2, - 0x46484, + 0x3e804, 0x2000c2, - 0x248343, - 0x20c302, - 0x22c0c3, - 0x232c43, + 0x202703, + 0x201242, + 0x214a83, + 0x232dc3, 0x200382, - 0x228b03, - 0x214543, - 0x211543, - 0x217b84, - 0x20a803, - 0x213dc3, - 0xca43, - 0x216603, - 0x2fe804, - 0x205b03, - 0x228b03, - 0x20c302, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x211543, - 0x20a803, - 0x20ca43, - 0x216603, - 0x3b8207, - 0x22c0c3, - 0x27c087, - 0x35f6c6, - 0x216b03, - 0x214403, - 0x228b03, - 0x204f43, - 0x224e44, - 0x300bc4, - 0x3187c6, - 0x218f83, - 0x20a803, - 0x216603, - 0x25cf45, - 0x34f1c4, - 0x326a03, - 0x276683, - 0x2c9ac7, - 0x20f805, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x211543, - 0x20a803, - 0x216603, - 0x14803, - 0x7970270c, - 0x50e87, - 0xbe846, - 0x114587, - 0x8f6c5, - 0x20be02, - 0x245a83, - 0x208b83, - 0x248343, - 0x7a22c0c3, - 0x207902, - 0x232c43, - 0x2020c3, - 0x228b03, - 0x224e44, - 0x201143, - 0x223bc3, - 0x211543, - 0x217b84, - 0x7a612b02, - 0x20a803, - 0x216603, - 0x21d0c3, - 0x22ce03, - 0x20a883, - 0x20ff42, - 0x205b03, - 0x9fe08, - 0x228b03, - 0x8303, - 0x322c44, - 0x248343, - 0x20c302, - 0x22c0c3, - 0x235604, - 0x232c43, - 0x228b03, - 0x224e44, - 0x214543, - 0x246b84, - 0x303f84, - 0x2d9bc6, - 0x217b84, - 0x20a803, - 0x216603, - 0x216103, - 0x24d686, - 0x3494b, - 0x39346, - 0x396ca, - 0x11960a, - 0x9fe08, - 0x225744, - 0x7ba2c0c3, - 0x3db044, - 0x232c43, - 0x26e144, - 0x228b03, - 0x220383, - 0x211543, - 0x20a803, - 0x6d9c3, - 0x216603, - 0x47203, - 0x34b00b, - 0x3c840a, - 0x3dc60c, - 0xe27c8, + 0x308003, + 0x21bc83, + 0x23c803, + 0x219a04, + 0x21a3c3, + 0x2125c3, + 0x3dc3, + 0x242543, + 0x30a104, + 0x207783, + 0x308003, + 0x201242, + 0x214a83, + 0x232dc3, + 0x308003, + 0x23c803, + 0x21a3c3, + 0x203dc3, + 0x242543, + 0x3bd187, + 0x214a83, + 0x27b0c7, + 0x397206, + 0x216c83, + 0x21bb43, + 0x308003, + 0x206c03, + 0x221dc4, + 0x28a404, + 0x3383c6, + 0x213a43, + 0x21a3c3, + 0x242543, + 0x24f8c5, + 0x2af384, + 0x323b43, + 0x2ce043, + 0x2d44c7, + 0x2cd845, + 0x68703, + 0x214a83, + 0x232dc3, + 0x308003, + 0x23c803, + 0x21a3c3, + 0x6e544, + 0x242543, + 0x14583, + 0x7c30988c, + 0x53547, + 0xe4846, + 0x91487, + 0x67f05, + 0x202b02, + 0x247403, + 0x214f03, + 0x202703, + 0x7ce14a83, + 0x208c02, + 0x232dc3, + 0x207083, + 0x308003, + 0x221dc4, + 0x2059c3, + 0x21b6c3, + 0x23c803, + 0x219a04, + 0x7d20ce02, + 0x21a3c3, + 0x242543, + 0x2308c3, + 0x21bd03, + 0x21a443, + 0x20c782, + 0x207783, + 0x9a048, + 0x308003, + 0x3a83, + 0x2135c4, + 0x202703, + 0x201242, + 0x214a83, + 0x235b44, + 0x232dc3, + 0x308003, + 0x221dc4, + 0x21bc83, + 0x3473c4, + 0x306c44, + 0x2e2406, + 0x219a04, + 0x21a3c3, + 0x242543, + 0x2141c3, + 0x253c46, + 0x34c8b, + 0x28886, + 0xec90a, + 0x11b94a, + 0x9a048, + 0x2136c4, + 0x7e614a83, + 0x2026c4, + 0x232dc3, + 0x270744, + 0x308003, + 0x2f3983, + 0x23c803, + 0x21a3c3, + 0x1b4103, + 0x242543, + 0x4cbc3, + 0x347f8b, + 0x3ca20a, + 0x3e010c, + 0xebe48, 0x2000c2, - 0x20c302, + 0x201242, 0x200382, - 0x22cd85, - 0x224e44, - 0x206a42, - 0x211543, - 0x303f84, - 0x205642, + 0x22d805, + 0x221dc4, + 0x209e82, + 0x23c803, + 0x306c44, + 0x208482, 0x2003c2, - 0x209482, - 0x20ff42, - 0x48343, - 0x9382, - 0x2c4009, - 0x364448, - 0x228989, - 0x208649, - 0x2181ca, - 0x22170a, - 0x203cc2, - 0x28cac2, - 0xc302, - 0x22c0c3, - 0x22ae02, - 0x23e746, - 0x378f82, - 0x201682, - 0x27018e, - 0x21604e, - 0x27fc47, - 0x20a787, - 0x24b5c2, - 0x232c43, - 0x228b03, - 0x20d602, + 0x2090c2, + 0x20c782, + 0x2703, + 0x15702, + 0x2cb209, + 0x365308, + 0x307e89, + 0x2073c9, + 0x20b40a, + 0x210f0a, + 0x206082, + 0x2167c2, + 0x1242, + 0x214a83, + 0x22ba02, + 0x240c46, + 0x377dc2, + 0x208d42, + 0x26fd0e, + 0x21410e, + 0x27e307, + 0x21a347, + 0x24dc82, + 0x232dc3, + 0x308003, + 0x210d82, 0x2005c2, - 0x14383, - 0x23580f, - 0x23ea82, - 0x366f87, - 0x2b1bc7, - 0x354207, - 0x2b590c, - 0x2e09cc, - 0x3d0384, - 0x39b8ca, - 0x211902, - 0x24e082, - 0x2bce04, + 0x1bac3, + 0x235d4f, + 0x21fb02, + 0x2b8887, + 0x3520c7, + 0x2bc287, + 0x2e9ccc, + 0x2dc18c, + 0x20c304, + 0x38d04a, + 0x214042, + 0x201e42, + 0x2c5104, 0x200702, - 0x2c4fc2, - 0x2e0c04, - 0x213ec2, - 0x203102, - 0xe403, - 0x29f5c7, - 0x238685, - 0x217002, - 0x23fb84, - 0x340d82, - 0x2e2548, - 0x20a803, - 0x377ec8, - 0x201fc2, - 0x3d0545, - 0x394d46, - 0x216603, - 0x208242, - 0x2f0ac7, - 0xb142, - 0x212ec5, - 0x301185, - 0x216442, - 0x2085c2, - 0x21cf0a, - 0x28a90a, - 0x287582, - 0x2a0cc4, - 0x205c42, - 0x20a288, - 0x205782, - 0x356708, + 0x2cc342, + 0x2dc3c4, + 0x20fe82, + 0x202042, + 0x1a8c3, + 0x299807, + 0x23a705, + 0x223502, + 0x23cd04, + 0x203f82, + 0x2eba08, + 0x21a3c3, + 0x376b08, + 0x2029c2, + 0x20c4c5, + 0x396e06, + 0x242543, + 0x20a882, + 0x2fa607, + 0xeb02, + 0x39e785, + 0x3c2f45, + 0x206442, + 0x20b382, + 0x33a90a, + 0x35094a, + 0x23c7c2, + 0x2a4284, + 0x203282, + 0x3d3788, + 0x20a5c2, + 0x359208, 0xf01, - 0x30ef47, - 0x310a49, - 0x212f42, - 0x316805, - 0x3b0205, - 0x21898b, - 0x318d4c, - 0x22a908, - 0x32e848, - 0x20b582, - 0x2a94c2, + 0x314447, + 0x3149c9, + 0x2b7402, + 0x319985, + 0x3b9c45, + 0x2184cb, + 0x33894c, + 0x22c088, + 0x32bb08, + 0x21d642, + 0x2ac882, 0x2000c2, - 0x9fe08, - 0x20c302, - 0x22c0c3, + 0x9a048, + 0x201242, + 0x214a83, 0x200382, - 0x205642, - 0xca43, + 0x208482, + 0x3dc3, 0x2003c2, - 0x216603, - 0x209482, + 0x242543, + 0x2090c2, 0x2000c2, - 0x12eb85, - 0x7ce0c302, - 0x7d628b03, - 0x20e403, - 0x206a42, - 0x20a803, - 0x3559c3, - 0x7da16603, - 0x2ed343, - 0x281ac6, - 0x160c603, - 0x12eb85, - 0x13390b, - 0x9fe08, - 0x7d27d6c8, - 0x7e407, - 0x6d247, - 0x175305, - 0x2a20d, - 0x39e82, - 0x115902, - 0xaa74a, - 0x8a747, - 0x27304, - 0x27343, - 0x1bffc4, - 0x7e204ec2, - 0x7e600ac2, - 0x7ea02282, - 0x7ee03342, - 0x7f209bc2, - 0x7f604042, - 0x176c87, - 0x7fa0c302, - 0x7fe2dac2, - 0x80221442, - 0x806081c2, - 0x216043, - 0x12704, - 0x236cc3, - 0x80a0c782, - 0x59648, - 0x80e076c2, - 0x4bc07, - 0x81200042, - 0x81600d82, - 0x81a00182, - 0x81e03dc2, - 0x82200f42, - 0x826005c2, - 0xd30c5, - 0x215183, - 0x36c284, - 0x82a00702, - 0x82e01882, - 0x83203c42, - 0x86ccb, - 0x83600c42, - 0x83e44502, - 0x84206a42, - 0x84606702, - 0x84a1d902, - 0x84e00bc2, - 0x85205a02, - 0x8566bf42, - 0x85a12b02, - 0x85e04f82, - 0x86205642, - 0x86636002, - 0x86a6f802, - 0x86e28c42, - 0x194584, - 0x217903, - 0x87200ec2, - 0x8760fc42, - 0x87a0ad82, - 0x87e006c2, - 0x882003c2, - 0x88600a82, - 0x198a47, - 0x88a16102, - 0x88e03d82, - 0x89209482, - 0x89616002, - 0x1a214c, - 0x89a47c82, - 0x89e22182, - 0x8a202682, - 0x8a617042, - 0x8aa00f02, - 0x8ae18342, - 0x8b205842, - 0x8b60b902, - 0x8ba75882, - 0x8be369c2, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x201143, - 0x17203, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x217203, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x83a01143, - 0x217203, - 0x3afd84, - 0x228886, - 0x2fd643, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x201143, - 0x217203, - 0x2bdd09, - 0x209382, - 0x39c403, - 0x2bacc3, - 0x36aa05, - 0x2020c3, - 0x201143, - 0x217203, - 0x28f543, - 0x221a43, - 0x34d8c9, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x217203, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x217203, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x201143, - 0x217203, - 0x209382, - 0x209382, - 0x201143, - 0x217203, - 0x8c62c0c3, - 0x232c43, - 0x208883, - 0x211543, - 0x20a803, - 0xca43, - 0x216603, - 0x9fe08, - 0x20c302, - 0x22c0c3, - 0x20a803, - 0x216603, - 0xbdb82, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x8d0ebe82, - 0x211543, - 0x20a803, - 0xca43, - 0x216603, - 0x15c1, - 0x249f84, - 0x20c302, - 0x22c0c3, + 0x139b05, + 0x7fa01242, + 0x1099c4, + 0x37e85, + 0x80708003, + 0x21a8c3, + 0x209e82, + 0x21a3c3, + 0x3b68c3, + 0x80a42543, + 0x2f7103, + 0x274d46, + 0x160e2c3, + 0x139b05, + 0x13f10b, + 0x9a048, + 0x7ff02e08, + 0x5c1c7, + 0x802c108a, + 0x6ddc7, + 0x97805, + 0x2a54d, + 0x8e242, + 0x118682, + 0xe01, + 0xad28a, + 0x150787, + 0x20c04, + 0x20c43, + 0x3c704, + 0x81202842, + 0x81600ac2, + 0x81a01182, + 0x81e02d02, + 0x82206b42, + 0x826086c2, + 0x17e707, + 0x82a01242, + 0x82e2ec02, + 0x8321f2c2, + 0x83602a42, + 0x214103, + 0xca04, + 0x22dcc3, + 0x83a0e442, + 0x5a988, + 0x83e015c2, + 0x4e2c7, + 0x1ad887, + 0x84200042, + 0x84600d82, + 0x84a00182, + 0x84e06182, + 0x85200f42, + 0x856005c2, + 0xf4185, + 0x24dec3, + 0x35c004, + 0x85a00702, + 0x85e14d42, + 0x86206002, + 0x7a04b, + 0x86600c42, + 0x86e01f42, + 0x87209e82, + 0x87610942, + 0x87a1d542, + 0x87e00bc2, + 0x88202382, + 0x8866c9c2, + 0x88a0ce02, + 0x88e03142, + 0x89208482, + 0x89637242, + 0x89a510c2, + 0x89e43802, + 0x5684, + 0x310543, + 0x8a200ec2, + 0x8a610e82, + 0x8aa0e742, + 0x8ae006c2, + 0x8b2003c2, + 0x8b600a82, + 0xf6bc8, + 0x91fc7, + 0x8ba141c2, + 0x8be06142, + 0x8c2090c2, + 0x8c6023c2, + 0x1aec8c, + 0x8ca02c02, + 0x8ce25b82, + 0x8d20f482, + 0x8d603642, + 0x8da00f02, + 0x8de0b582, + 0x8e201342, + 0x8e607302, + 0x8ea76002, + 0x8ee76542, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x2059c3, + 0x23703, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x223703, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x86a059c3, + 0x223703, + 0x3c0b44, + 0x307d86, + 0x306403, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x2059c3, + 0x223703, + 0x374689, + 0x215702, + 0x39b6c3, + 0x2c2a43, + 0x2894c5, + 0x207083, + 0x2059c3, + 0x223703, + 0x267d83, + 0x211243, + 0x3c4409, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x223703, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x223703, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x223703, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x2059c3, + 0x223703, + 0x215702, + 0x215702, + 0x2059c3, + 0x223703, + 0x8f614a83, + 0x232dc3, + 0x207603, + 0x23c803, + 0x21a3c3, + 0x3dc3, + 0x242543, + 0x9a048, + 0x201242, + 0x214a83, + 0x21a3c3, + 0x242543, + 0x141842, + 0x214a83, + 0x232dc3, + 0x308003, + 0x901192c2, + 0x23c803, + 0x21a3c3, + 0x3dc3, + 0x242543, + 0x1301, + 0x24c0c4, + 0x201242, + 0x214a83, 0x200983, - 0x232c43, - 0x24b304, - 0x212483, - 0x228b03, - 0x224e44, - 0x214543, - 0x211543, - 0x20a803, - 0x216603, - 0x236bc3, - 0x204185, - 0x221a43, - 0x205b03, - 0xca43, - 0x20c302, - 0x22c0c3, - 0x201143, - 0x20a803, - 0x216603, + 0x232dc3, + 0x24d9c4, + 0x228503, + 0x308003, + 0x221dc4, + 0x21bc83, + 0x23c803, + 0x21a3c3, + 0x242543, + 0x22b983, + 0x208805, + 0x211243, + 0x207783, + 0x882, + 0x3dc3, + 0x201242, + 0x214a83, + 0x2059c3, + 0x21a3c3, + 0x242543, 0x2000c2, - 0x248343, - 0x9fe08, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x22f446, - 0x224e44, - 0x214543, - 0x217b84, - 0x20a803, - 0x216603, - 0x216103, - 0x22c0c3, - 0x232c43, - 0x20a803, - 0x216603, - 0x2d7c2, - 0x1942, - 0x1458787, - 0x141347, - 0x22c0c3, - 0x39346, - 0x232c43, - 0x228b03, - 0xe7d46, - 0x20a803, - 0x216603, - 0x32b688, - 0x32e689, - 0x341509, - 0x34cd48, - 0x396f48, - 0x396f49, - 0x32370a, - 0x35f9ca, - 0x39278a, - 0x39914a, - 0x3c840a, - 0x3d5fcb, - 0x23d20d, - 0x367bcf, - 0x25b050, - 0x36144d, - 0x37e04c, - 0x398e8b, - 0x6d448, - 0xebcc8, - 0x92e85, - 0x1488147, - 0xccc85, + 0x202703, + 0x9a048, + 0x214a83, + 0x232dc3, + 0x308003, + 0x22f7c6, + 0x221dc4, + 0x21bc83, + 0x219a04, + 0x21a3c3, + 0x242543, + 0x2141c3, + 0x29904, + 0x214a83, + 0x239c3, + 0x232dc3, + 0x9e82, + 0x21a3c3, + 0x242543, + 0x2aec2, + 0x2982, + 0x147ee07, + 0x1807, + 0x214a83, + 0x28886, + 0x232dc3, + 0x308003, + 0xedf86, + 0x21a3c3, + 0x242543, + 0x328e48, + 0x32b949, + 0x33e209, + 0x34ae08, + 0x399488, + 0x399489, + 0x322c0a, + 0x3602ca, + 0x39424a, + 0x39abca, + 0x3ca20a, + 0x3d818b, + 0x30838d, + 0x23fd4f, + 0x35d210, + 0x361d4d, + 0x37d8cc, + 0x39a90b, + 0x6dfc8, + 0x11d548, + 0x19d705, + 0x1486107, + 0xd7445, 0x2000c2, - 0x20f645, - 0x20e3c3, - 0x9060c302, - 0x232c43, - 0x228b03, - 0x3d4007, - 0x20a443, - 0x211543, - 0x20a803, - 0x24bbc3, - 0x213dc3, - 0x209a83, - 0x20ca43, - 0x216603, - 0x253c46, - 0x219f82, - 0x205b03, - 0x9fe08, + 0x2cd685, + 0x202003, + 0x93601242, + 0x232dc3, + 0x308003, + 0x27e7c7, + 0x25cc03, + 0x23c803, + 0x21a3c3, + 0x24e283, + 0x2125c3, + 0x206a03, + 0x203dc3, + 0x242543, + 0x252b06, + 0x233442, + 0x207783, + 0x9a048, 0x2000c2, - 0x248343, - 0x20c302, - 0x22c0c3, - 0x232c43, - 0x228b03, - 0x224e44, - 0x211543, - 0x20a803, - 0x216603, - 0x20c603, - 0x141347, - 0x8582, - 0x2b44, - 0x15c87c6, + 0x202703, + 0x201242, + 0x214a83, + 0x232dc3, + 0x308003, + 0x221dc4, + 0x23c803, + 0x21a3c3, + 0x242543, + 0x20e2c3, + 0x1807, + 0xb342, + 0x68b44, + 0x151c306, 0x2000c2, - 0x20c302, - 0x228b03, - 0x211543, - 0x216603, + 0x201242, + 0x308003, + 0x23c803, + 0x242543, } // children is the list of nodes' children, the parent's wildcard bit and the @@ -9462,18 +9554,18 @@ var children = [...]uint32{ 0x40000000, 0x50000000, 0x60000000, - 0x17f85f8, - 0x17fc5fe, - 0x18005ff, - 0x1824600, - 0x1980609, - 0x1998660, - 0x19ac666, - 0x19c466b, - 0x19e4671, - 0x19fc679, - 0x1a1467f, - 0x1a2c685, + 0x17ec5f5, + 0x17f05fb, + 0x17f45fc, + 0x18185fd, + 0x1970606, + 0x198865c, + 0x199c662, + 0x19b4667, + 0x19d466d, + 0x19f4675, + 0x1a0c67d, + 0x1a2c683, 0x1a3068b, 0x1a5868c, 0x1a5c696, @@ -9482,516 +9574,501 @@ var children = [...]uint32{ 0x1a7c69e, 0x1ab869f, 0x1abc6ae, - 0x61ac46af, - 0x21acc6b1, - 0x1b146b3, - 0x1b186c5, - 0x1b3c6c6, - 0x1b406cf, + 0x1ac06af, + 0x61ac86b0, + 0x21ad06b2, + 0x1b186b4, + 0x1b1c6c6, + 0x1b406c7, 0x1b446d0, - 0x1b586d1, - 0x1b5c6d6, - 0x1b8c6d7, - 0x1ba86e3, - 0x1bd06ea, - 0x1be06f4, - 0x1be46f8, - 0x1c7c6f9, - 0x1c9071f, - 0x1ca4724, - 0x1cdc729, - 0x1cec737, - 0x1d0073b, - 0x1d18740, - 0x1dbc746, - 0x1fc076f, - 0x1fc47f0, - 0x20307f1, - 0x209c80c, - 0x20b4827, - 0x20c882d, - 0x20cc832, - 0x20d4833, - 0x20e8835, - 0x20ec83a, - 0x210883b, - 0x2158842, - 0x215c856, - 0x22160857, - 0x217c858, - 0x218085f, + 0x1b486d1, + 0x1b5c6d2, + 0x1b606d7, + 0x1b806d8, + 0x1bb06e0, + 0x1bcc6ec, + 0x1bf46f3, + 0x1c046fd, + 0x1c08701, + 0x1ca0702, + 0x1cb4728, + 0x1cc872d, + 0x1d00732, + 0x1d10740, + 0x1d24744, + 0x1d3c749, + 0x1de074f, + 0x1fe4778, + 0x1fe87f9, + 0x20547fa, + 0x20c0815, + 0x20d8830, + 0x20ec836, + 0x20f083b, + 0x20f883c, + 0x210c83e, + 0x2110843, + 0x2130844, + 0x218084c, 0x2184860, - 0x21a8861, - 0x21e886a, - 0x21ec87a, - 0x621f087b, - 0x220887c, - 0x222c882, - 0x223888b, - 0x224888e, - 0x22fc892, - 0x23008bf, - 0x223108c0, - 0x223148c4, - 0x2231c8c5, - 0x23748c7, - 0x23788dd, - 0x288c8de, - 0x2890a23, - 0x22938a24, - 0x2293ca4e, - 0x22940a4f, - 0x2294ca50, - 0x22950a53, - 0x2295ca54, - 0x22960a57, - 0x22964a58, - 0x22968a59, - 0x2296ca5a, - 0x22970a5b, - 0x2297ca5c, - 0x22980a5f, - 0x2298ca60, + 0x22188861, + 0x21a4862, + 0x21a8869, + 0x21ac86a, + 0x21d086b, + 0x2214874, + 0x2218885, + 0x6221c886, + 0x2238887, + 0x226488e, + 0x2270899, + 0x228089c, + 0x23348a0, + 0x23388cd, + 0x223488ce, + 0x2234c8d2, + 0x223548d3, + 0x23ac8d5, + 0x23b08eb, + 0x23b48ec, + 0x28dc8ed, + 0x28e0a37, + 0x22988a38, + 0x2298ca62, 0x22990a63, - 0x22994a64, - 0x22998a65, - 0x229a4a66, - 0x229a8a69, - 0x229b4a6a, + 0x2299ca64, + 0x229a0a67, + 0x229aca68, + 0x229b0a6b, + 0x229b4a6c, 0x229b8a6d, 0x229bca6e, 0x229c0a6f, - 0x29c4a70, - 0x229c8a71, - 0x229d4a72, - 0x229d8a75, - 0x29dca76, - 0x29e4a77, - 0x629f0a79, - 0x2a34a7c, - 0x22a54a8d, - 0x22a58a95, - 0x22a5ca96, - 0x22a64a97, - 0x22a68a99, - 0x2a6ca9a, - 0x22a70a9b, - 0x22a74a9c, - 0x22a78a9d, - 0x22a7ca9e, - 0x2a84a9f, - 0x2a8caa1, - 0x2a90aa3, - 0x2aacaa4, - 0x2ac4aab, - 0x2ac8ab1, - 0x2ad8ab2, - 0x2ae4ab6, - 0x2b18ab9, + 0x229cca70, + 0x229d0a73, + 0x229dca74, + 0x229e0a77, + 0x229e4a78, + 0x229e8a79, + 0x229f4a7a, + 0x229f8a7d, + 0x22a04a7e, + 0x22a08a81, + 0x22a0ca82, + 0x22a10a83, + 0x2a14a84, + 0x22a18a85, + 0x22a24a86, + 0x22a28a89, + 0x2a2ca8a, + 0x2a34a8b, + 0x62a40a8d, + 0x2a84a90, + 0x22aa4aa1, + 0x22aa8aa9, + 0x22aacaaa, + 0x22ab0aab, + 0x22ab8aac, + 0x22abcaae, + 0x2ac0aaf, + 0x22ac4ab0, + 0x22ac8ab1, + 0x22accab2, + 0x22ad0ab3, + 0x2ad8ab4, + 0x2ae0ab6, + 0x2ae4ab8, + 0x2b00ab9, + 0x2b18ac0, 0x2b1cac6, - 0x2b34ac7, - 0x22b3cacd, - 0x22b40acf, - 0x22b48ad0, - 0x2c40ad2, - 0x22c44b10, - 0x2c4cb11, - 0x2c50b13, - 0x22c54b14, - 0x2c58b15, - 0x2c70b16, - 0x2c74b1c, - 0x2c78b1d, - 0x2c7cb1e, - 0x2c94b1f, - 0x2ca8b25, - 0x2cd0b2a, - 0x2cf0b34, - 0x2cf4b3c, - 0x62cf8b3d, - 0x2d2cb3e, - 0x2d30b4b, - 0x22d34b4c, - 0x2d38b4d, - 0x2d60b4e, + 0x2b2cac7, + 0x2b38acb, + 0x2b6cace, + 0x2b74adb, + 0x22b78add, + 0x2b90ade, + 0x22b98ae4, + 0x22b9cae6, + 0x22ba4ae7, + 0x2ca0ae9, + 0x22ca4b28, + 0x2cacb29, + 0x2cb0b2b, + 0x22cb4b2c, + 0x2cb8b2d, + 0x2ce0b2e, + 0x2ce4b38, + 0x2ce8b39, + 0x2cecb3a, + 0x2d04b3b, + 0x2d18b41, + 0x2d40b46, + 0x2d60b50, 0x2d64b58, - 0x2d88b59, - 0x2d8cb62, - 0x2da0b63, - 0x2da4b68, + 0x62d68b59, + 0x2d9cb5a, + 0x2da0b67, + 0x22da4b68, 0x2da8b69, - 0x2dc8b6a, - 0x2de4b72, - 0x2de8b79, - 0x22decb7a, - 0x2df0b7b, - 0x2df4b7c, - 0x2df8b7d, - 0x2e00b7e, - 0x2e14b80, + 0x2dd0b6a, + 0x2dd4b74, + 0x2df8b75, + 0x2dfcb7e, + 0x2e10b7f, + 0x2e14b84, 0x2e18b85, - 0x2e1cb86, - 0x2e44b87, - 0x2e48b91, - 0x2ebcb92, - 0x2ec0baf, - 0x2ec4bb0, - 0x2ee4bb1, - 0x2ef8bb9, - 0x2f0cbbe, - 0x2f24bc3, - 0x2f40bc9, - 0x2f58bd0, - 0x2f5cbd6, - 0x2f74bd7, - 0x2f90bdd, - 0x2f94be4, - 0x2fb4be5, - 0x2fd4bed, - 0x2ff0bf5, - 0x3054bfc, - 0x3070c15, - 0x3080c1c, - 0x3084c20, - 0x309cc21, - 0x30e0c27, - 0x3160c38, - 0x3190c58, - 0x3194c64, - 0x31a0c65, - 0x31c0c68, - 0x31c4c70, - 0x31e8c71, - 0x31f0c7a, - 0x322cc7c, - 0x327cc8b, - 0x3280c9f, - 0x3284ca0, - 0x3354ca1, - 0x23358cd5, - 0x2335ccd6, - 0x3360cd7, - 0x23364cd8, - 0x23368cd9, - 0x336ccda, - 0x23370cdb, - 0x23380cdc, - 0x23384ce0, - 0x23388ce1, - 0x2338cce2, - 0x23390ce3, - 0x33a8ce4, - 0x33cccea, - 0x33eccf3, - 0x3a58cfb, - 0x3a64e96, - 0x3a84e99, - 0x3c44ea1, - 0x3d14f11, - 0x3d84f45, - 0x3ddcf61, - 0x3ec4f77, - 0x3f1cfb1, - 0x3f58fc7, - 0x4054fd6, - 0x4121015, - 0x41b9048, - 0x424906e, - 0x42ad092, - 0x44e50ab, - 0x459d139, - 0x4669167, - 0x46b519a, - 0x473d1ad, - 0x47791cf, - 0x47c91de, - 0x48411f2, - 0x64845210, - 0x64849211, - 0x6484d212, - 0x48c9213, - 0x4925232, - 0x49a1249, - 0x4a19268, - 0x4a99286, - 0x4b052a6, - 0x4c312c1, - 0x4c8930c, - 0x64c8d322, - 0x4d25323, - 0x4d2d349, - 0x24d3134b, - 0x4db934c, - 0x4e0536e, - 0x4e6d381, - 0x4f1539b, - 0x4fdd3c5, - 0x50453f7, - 0x5159411, - 0x6515d456, - 0x65161457, - 0x51bd458, - 0x521946f, - 0x52a9486, - 0x53254aa, - 0x53694c9, - 0x544d4da, - 0x5481513, - 0x54e1520, - 0x5555538, - 0x55dd555, - 0x561d577, - 0x568d587, - 0x656915a3, - 0x56b95a4, - 0x56bd5ae, - 0x56d55af, - 0x56f15b5, - 0x57355bc, - 0x57455cd, - 0x575d5d1, - 0x57d55d7, - 0x57dd5f5, - 0x57f95f7, - 0x580d5fe, - 0x5829603, - 0x585560a, - 0x5859615, - 0x5861616, - 0x5875618, - 0x589561d, - 0x58a5625, - 0x58b1629, - 0x58ed62c, - 0x58f563b, - 0x590963d, - 0x592d642, - 0x593964b, - 0x594164e, - 0x5965650, - 0x5989659, - 0x59a1662, - 0x59a5668, - 0x59ad669, - 0x59b166b, - 0x5a5166c, - 0x5a55694, - 0x5a59695, - 0x5a5d696, - 0x5a81697, - 0x5aa56a0, - 0x5ac16a9, - 0x5ad56b0, - 0x5ae96b5, - 0x5af16ba, - 0x5af96bc, - 0x5b016be, - 0x5b196c0, - 0x5b296c6, - 0x5b2d6ca, - 0x5b496cb, - 0x63d16d2, - 0x64098f4, - 0x6435902, - 0x645190d, - 0x6471914, - 0x649191c, - 0x64d5924, - 0x64dd935, - 0x264e1937, - 0x264e5938, - 0x64ed939, - 0x66c593b, - 0x266c99b1, - 0x66cd9b2, - 0x266dd9b3, - 0x266e59b7, - 0x266f19b9, - 0x66f59bc, - 0x266fd9bd, - 0x67059bf, - 0x67159c1, - 0x673d9c5, - 0x67799cf, - 0x677d9de, - 0x67b59df, - 0x67d99ed, - 0x73319f6, - 0x7335ccc, - 0x7339ccd, - 0x2733dcce, - 0x7341ccf, - 0x27345cd0, - 0x7349cd1, - 0x27355cd2, - 0x7359cd5, - 0x735dcd6, - 0x27361cd7, - 0x7365cd8, - 0x2736dcd9, - 0x7371cdb, - 0x7375cdc, - 0x27385cdd, - 0x7389ce1, - 0x738dce2, - 0x7391ce3, - 0x7395ce4, - 0x27399ce5, - 0x739dce6, - 0x73a1ce7, - 0x73a5ce8, - 0x73a9ce9, - 0x273b1cea, - 0x73b5cec, - 0x73b9ced, - 0x73bdcee, - 0x273c1cef, - 0x73c5cf0, - 0x273cdcf1, - 0x273d1cf3, - 0x73edcf4, - 0x7405cfb, - 0x27409d01, - 0x744dd02, - 0x7451d13, - 0x7475d14, - 0x7481d1d, - 0x7485d20, - 0x7489d21, - 0x7645d22, - 0x27649d91, - 0x27651d92, - 0x27655d94, - 0x27659d95, - 0x7661d96, - 0x773dd98, - 0x27749dcf, - 0x2774ddd2, - 0x27751dd3, - 0x27755dd4, - 0x7759dd5, - 0x7785dd6, - 0x7789de1, - 0x778dde2, - 0x77b1de3, - 0x77bddec, - 0x77dddef, - 0x77e1df7, - 0x7819df8, - 0x7ac9e06, - 0x7b85eb2, - 0x7b89ee1, - 0x7b8dee2, - 0x7ba1ee3, - 0x7bd5ee8, - 0x7c0def5, - 0x27c11f03, - 0x7c2df04, - 0x7c55f0b, - 0x7c59f15, - 0x7c7df16, - 0x7c99f1f, - 0x7cc1f26, - 0x7cd1f30, - 0x7cd5f34, - 0x7cd9f35, - 0x7d11f36, - 0x7d1df44, - 0x7d45f47, - 0x7dc5f51, - 0x27dc9f71, - 0x7dd9f72, - 0x7de9f76, - 0x7e05f7a, - 0x7e25f81, - 0x7e29f89, - 0x7e3df8a, - 0x7e51f8f, - 0x7e55f94, - 0x7e59f95, - 0x7e5df96, - 0x7e7df97, - 0x7f25f9f, - 0x7f29fc9, - 0x7f45fca, - 0x7f69fd1, - 0x7f6dfda, - 0x7f75fdb, - 0x7f91fdd, - 0x7f99fe4, - 0x7fadfe6, - 0x7fcdfeb, - 0x7fe9ff3, - 0x7ff5ffa, - 0x800dffd, - 0x8046003, - 0x811a011, - 0x811e046, - 0x8132047, - 0x813a04c, - 0x815204e, - 0x8156054, - 0x8162055, - 0x8166058, - 0x816a059, - 0x816e05a, - 0x819205b, - 0x81d2064, - 0x81d6074, - 0x81f6075, - 0x824607d, - 0x826a091, - 0x2826e09a, - 0x827609b, - 0x82ce09d, - 0x82d20b3, - 0x82d60b4, - 0x82da0b5, - 0x831e0b6, - 0x832e0c7, - 0x836e0cb, - 0x83720db, - 0x83a20dc, - 0x84ee0e8, - 0x851613b, - 0x8546145, - 0x8566151, - 0x2856e159, - 0x857615b, - 0x858215d, - 0x8696160, - 0x86a21a5, - 0x86ae1a8, - 0x86ba1ab, - 0x86c61ae, - 0x86d21b1, - 0x86de1b4, - 0x86ea1b7, - 0x86f61ba, - 0x87021bd, - 0x870e1c0, - 0x871a1c3, - 0x87261c6, - 0x87321c9, - 0x873a1cc, - 0x87461ce, - 0x87521d1, - 0x875e1d4, - 0x876a1d7, - 0x87761da, - 0x87821dd, - 0x878e1e0, - 0x879a1e3, - 0x87a61e6, - 0x87b21e9, - 0x87be1ec, - 0x87ea1ef, - 0x87f61fa, - 0x88021fd, - 0x880e200, - 0x881a203, - 0x8826206, - 0x882e209, + 0x2e38b86, + 0x2e54b8e, + 0x2e58b95, + 0x22e5cb96, + 0x2e60b97, + 0x2e64b98, + 0x2e68b99, + 0x2e70b9a, + 0x2e84b9c, + 0x2e88ba1, + 0x2e8cba2, + 0x2eb4ba3, + 0x2eb8bad, + 0x2f2cbae, + 0x2f30bcb, + 0x2f34bcc, + 0x2f54bcd, + 0x2f6cbd5, + 0x2f70bdb, + 0x2f84bdc, + 0x2f9cbe1, + 0x2fbcbe7, + 0x2fd4bef, + 0x2fd8bf5, + 0x2ff4bf6, + 0x3010bfd, + 0x3014c04, + 0x3040c05, + 0x3060c10, + 0x3080c18, + 0x30e4c20, + 0x3104c39, + 0x3120c41, + 0x3124c48, + 0x313cc49, + 0x3180c4f, + 0x3200c60, + 0x3230c80, + 0x3234c8c, + 0x3240c8d, + 0x3260c90, + 0x3264c98, + 0x3288c99, + 0x3290ca2, + 0x32ccca4, + 0x3320cb3, + 0x3324cc8, + 0x3328cc9, + 0x3404cca, + 0x2340cd01, + 0x23410d03, + 0x23414d04, + 0x3418d05, + 0x2341cd06, + 0x23420d07, + 0x3424d08, + 0x23428d09, + 0x23438d0a, + 0x2343cd0e, + 0x23440d0f, + 0x23444d10, + 0x23448d11, + 0x2344cd12, + 0x3464d13, + 0x3488d19, + 0x34a8d22, + 0x3b14d2a, + 0x3b20ec5, + 0x3b40ec8, + 0x3d00ed0, + 0x3dd0f40, + 0x3e40f74, + 0x3e98f90, + 0x3f80fa6, + 0x3fd8fe0, + 0x4014ff6, + 0x4111005, + 0x41dd044, + 0x4275077, + 0x430509d, + 0x43690c1, + 0x45a10da, + 0x4659168, + 0x4725196, + 0x47711c9, + 0x47f91dc, + 0x48351fe, + 0x488520d, + 0x48fd221, + 0x6490123f, + 0x64905240, + 0x64909241, + 0x4985242, + 0x49e1261, + 0x4a5d278, + 0x4ad5297, + 0x4b552b5, + 0x4bc12d5, + 0x4ced2f0, + 0x4d4533b, + 0x64d49351, + 0x4de1352, + 0x4de9378, + 0x24ded37a, + 0x4e7537b, + 0x4ec139d, + 0x4f293b0, + 0x4fd13ca, + 0x50993f4, + 0x5101426, + 0x5215440, + 0x65219485, + 0x6521d486, + 0x5279487, + 0x52d549e, + 0x53654b5, + 0x53e14d9, + 0x54254f8, + 0x5509509, + 0x553d542, + 0x559d54f, + 0x5611567, + 0x5699584, + 0x56d95a6, + 0x57495b6, + 0x6574d5d2, + 0x57755d3, + 0x57795dd, + 0x57a95de, + 0x57c55ea, + 0x58095f1, + 0x5819602, + 0x5831606, + 0x58a960c, + 0x58b162a, + 0x58cd62c, + 0x58e1633, + 0x58fd638, + 0x592963f, + 0x592d64a, + 0x593564b, + 0x594964d, + 0x5969652, + 0x597965a, + 0x598565e, + 0x59c1661, + 0x59c9670, + 0x59dd672, + 0x5a05677, + 0x5a11681, + 0x5a19684, + 0x5a41686, + 0x5a65690, + 0x5a7d699, + 0x5a8169f, + 0x5a896a0, + 0x5a9d6a2, + 0x5b456a7, + 0x5b496d1, + 0x5b4d6d2, + 0x5b516d3, + 0x5b756d4, + 0x5b996dd, + 0x5bb56e6, + 0x5bc96ed, + 0x5bdd6f2, + 0x5be56f7, + 0x5bed6f9, + 0x5bf56fb, + 0x5c0d6fd, + 0x5c1d703, + 0x5c21707, + 0x5c3d708, + 0x64c570f, + 0x64fd931, + 0x652993f, + 0x654594a, + 0x6565951, + 0x6585959, + 0x65c9961, + 0x65d1972, + 0x265d5974, + 0x265d9975, + 0x65e1976, + 0x67cd978, + 0x267d19f3, + 0x67d59f4, + 0x267d99f5, + 0x267e99f6, + 0x267f19fa, + 0x267fd9fc, + 0x68019ff, + 0x26809a00, + 0x6811a02, + 0x6821a04, + 0x6849a08, + 0x6885a12, + 0x6889a21, + 0x68c1a22, + 0x68e5a30, + 0x743da39, + 0x7441d0f, + 0x7445d10, + 0x27449d11, + 0x744dd12, + 0x27451d13, + 0x7455d14, + 0x27461d15, + 0x7465d18, + 0x7469d19, + 0x2746dd1a, + 0x7471d1b, + 0x27479d1c, + 0x747dd1e, + 0x7481d1f, + 0x27491d20, + 0x7495d24, + 0x7499d25, + 0x749dd26, + 0x74a1d27, + 0x274a5d28, + 0x74a9d29, + 0x74add2a, + 0x74b1d2b, + 0x74b5d2c, + 0x274bdd2d, + 0x74c1d2f, + 0x74c5d30, + 0x74c9d31, + 0x274cdd32, + 0x74d1d33, + 0x274d9d34, + 0x274ddd36, + 0x74f9d37, + 0x7511d3e, + 0x7555d44, + 0x7559d55, + 0x757dd56, + 0x7589d5f, + 0x758dd62, + 0x7591d63, + 0x7755d64, + 0x27759dd5, + 0x27761dd6, + 0x27765dd8, + 0x27769dd9, + 0x7771dda, + 0x784dddc, + 0x27859e13, + 0x2785de16, + 0x27861e17, + 0x27865e18, + 0x7869e19, + 0x7895e1a, + 0x78a1e25, + 0x78a5e28, + 0x78c9e29, + 0x78d5e32, + 0x78f5e35, + 0x78f9e3d, + 0x7931e3e, + 0x7be1e4c, + 0x7c9def8, + 0x7ca1f27, + 0x7ca5f28, + 0x7cb9f29, + 0x7cbdf2e, + 0x7cf1f2f, + 0x7d29f3c, + 0x27d2df4a, + 0x7d49f4b, + 0x7d71f52, + 0x7d75f5c, + 0x7d99f5d, + 0x7db5f66, + 0x7dddf6d, + 0x7dedf77, + 0x7df1f7b, + 0x7df5f7c, + 0x7e2df7d, + 0x7e39f8b, + 0x7e61f8e, + 0x7ee1f98, + 0x27ee5fb8, + 0x7ef5fb9, + 0x7f05fbd, + 0x7f21fc1, + 0x7f41fc8, + 0x7f45fd0, + 0x7f59fd1, + 0x7f6dfd6, + 0x7f71fdb, + 0x7f75fdc, + 0x7f79fdd, + 0x7f99fde, + 0x8041fe6, + 0x8046010, + 0x8062011, + 0x808a018, + 0x808e022, + 0x8096023, + 0x80ba025, + 0x80c202e, + 0x80d6030, + 0x80f6035, + 0x811203d, + 0x8122044, + 0x813a048, + 0x817204e, + 0x817605c, + 0x824a05d, + 0x824e092, + 0x8262093, + 0x826a098, + 0x828209a, + 0x82860a0, + 0x82920a1, + 0x829e0a4, + 0x82a20a7, + 0x82a60a8, + 0x82aa0a9, + 0x82ce0aa, + 0x830e0b3, + 0x83120c3, + 0x83320c4, + 0x83820cc, + 0x83ae0e0, + 0x283b20eb, + 0x83ba0ec, + 0x84120ee, + 0x8416104, + 0x841a105, + 0x841e106, + 0x8462107, + 0x8472118, + 0x84b211c, + 0x84b612c, + 0x84e612d, + 0x8632139, + 0x865a18c, + 0x8692196, + 0x86b61a4, + 0x286be1ad, + 0x286c21af, + 0x86ca1b0, + 0x86d61b2, + 0x87f21b5, + 0x87fe1fc, + 0x880a1ff, + 0x8816202, + 0x8822205, + 0x882e208, 0x883a20b, 0x884620e, 0x8852211, @@ -10000,47 +10077,74 @@ var children = [...]uint32{ 0x887621a, 0x888221d, 0x888e220, - 0x889a223, - 0x88a6226, - 0x88b2229, - 0x88be22c, - 0x88ca22f, - 0x88d2232, + 0x8896223, + 0x88a2225, + 0x88ae228, + 0x88ba22b, + 0x88c622e, + 0x88d2231, 0x88de234, 0x88ea237, 0x88f623a, 0x890223d, 0x890e240, 0x891a243, - 0x8926246, - 0x8932249, - 0x893624c, - 0x894224d, - 0x895e250, - 0x8962257, - 0x8972258, - 0x899625c, - 0x899a265, - 0x89de266, - 0x89e2277, - 0x89f6278, - 0x8a2a27d, - 0x8a3a28a, - 0x8a4228e, - 0x8a66290, - 0x8a7e299, - 0x8a9629f, - 0x8aae2a5, - 0x8ac22ab, - 0x28b0a2b0, - 0x8b0e2c2, - 0x8b3a2c3, - 0x8b4a2ce, - 0x8b5e2d2, + 0x8946246, + 0x8952251, + 0x895e254, + 0x896a257, + 0x897625a, + 0x898225d, + 0x898a260, + 0x8996262, + 0x89a2265, + 0x89ae268, + 0x89ba26b, + 0x89c626e, + 0x89d2271, + 0x89de274, + 0x89ea277, + 0x89f627a, + 0x8a0227d, + 0x8a0e280, + 0x8a16283, + 0x8a22285, + 0x8a2a288, + 0x8a3628a, + 0x8a4228d, + 0x8a4e290, + 0x8a5a293, + 0x8a66296, + 0x8a72299, + 0x8a7e29c, + 0x8a8a29f, + 0x8a8e2a2, + 0x8a9a2a3, + 0x8ab62a6, + 0x8aba2ad, + 0x8aca2ae, + 0x8aee2b2, + 0x8af22bb, + 0x8b362bc, + 0x8b3e2cd, + 0x8b522cf, + 0x8b862d4, + 0x8ba22e1, + 0x8baa2e8, + 0x8bce2ea, + 0x8be62f3, + 0x8bfe2f9, + 0x8c162ff, + 0x8c2a305, + 0x28c7230a, + 0x8c7631c, + 0x8ca231d, + 0x8cb2328, + 0x8cc632c, } -// max children 580 (capacity 1023) -// max text offset 30618 (capacity 32767) +// max children 592 (capacity 1023) +// max text offset 30772 (capacity 32767) // max text length 36 (capacity 63) -// max hi 8919 (capacity 16383) -// max lo 8914 (capacity 16383) +// max hi 9009 (capacity 16383) +// max lo 9004 (capacity 16383) diff --git a/vendor/modules.txt b/vendor/modules.txt index 02a864a4f5587..14c90007b37c2 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -317,7 +317,7 @@ github.com/go-git/go-git/v5/utils/merkletrie/filesystem github.com/go-git/go-git/v5/utils/merkletrie/index github.com/go-git/go-git/v5/utils/merkletrie/internal/frame github.com/go-git/go-git/v5/utils/merkletrie/noder -# github.com/go-ini/ini v1.56.0 +# github.com/go-ini/ini v1.57.0 ## explicit github.com/go-ini/ini # github.com/go-openapi/analysis v0.19.5 From 60f6582d68e212d3205f1edcafc3620d6498fdd5 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 21 Jun 2020 21:00:08 +0800 Subject: [PATCH 17/59] Fix test --- .drone.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index 0079fc63116a9..354c4ce006d49 100644 --- a/.drone.yml +++ b/.drone.yml @@ -299,7 +299,7 @@ services: - name: minio image: minio/minio:RELEASE.2020-05-16T01-33-21Z commands: - - minio server ./data + - minio server /data environment: MINIO_ACCESS_KEY: 123456 MINIO_SECRET_KEY: 123456 From 8547e77c7cf3154745300f35dcde91c8d322b410 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 22 Jun 2020 21:01:24 +0800 Subject: [PATCH 18/59] display the error on console --- integrations/sqlite.ini.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/integrations/sqlite.ini.tmpl b/integrations/sqlite.ini.tmpl index db171c2eecef6..ad79d2e8c5959 100644 --- a/integrations/sqlite.ini.tmpl +++ b/integrations/sqlite.ini.tmpl @@ -66,12 +66,12 @@ PROVIDER = file PROVIDER_CONFIG = integrations/gitea-integration-sqlite/data/sessions [log] -MODE = test,file +MODE = test,file,console ROOT_PATH = sqlite-log REDIRECT_MACARON_LOG = true ROUTER = , MACARON = , -XORM = file +XORM = file,console [log.test] LEVEL = Info From edcb3004958fea55321b00be38aa37d5201f5971 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 23 Jun 2020 20:12:20 +0800 Subject: [PATCH 19/59] Move minio test to amd64 since minio docker don't support arm64 --- .drone.yml | 16 ++++++++-------- integrations/mysql.ini.tmpl | 9 ++++++++- integrations/sqlite.ini.tmpl | 12 +----------- 3 files changed, 17 insertions(+), 20 deletions(-) diff --git a/.drone.yml b/.drone.yml index 354c4ce006d49..ddcd582f400b8 100644 --- a/.drone.yml +++ b/.drone.yml @@ -151,6 +151,14 @@ services: discovery.type: single-node image: elasticsearch:7.5.0 + - name: minio + image: minio/minio:RELEASE.2020-05-16T01-33-21Z + commands: + - minio server /data + environment: + MINIO_ACCESS_KEY: 123456 + MINIO_SECRET_KEY: 123456 + steps: - name: fetch-tags pull: default @@ -296,14 +304,6 @@ services: pull: default image: gitea/test-openldap:latest - - name: minio - image: minio/minio:RELEASE.2020-05-16T01-33-21Z - commands: - - minio server /data - environment: - MINIO_ACCESS_KEY: 123456 - MINIO_SECRET_KEY: 123456 - steps: - name: fetch-tags pull: default diff --git a/integrations/mysql.ini.tmpl b/integrations/mysql.ini.tmpl index 012b0aef88062..57874f9354fbb 100644 --- a/integrations/mysql.ini.tmpl +++ b/integrations/mysql.ini.tmpl @@ -42,7 +42,14 @@ APP_DATA_PATH = integrations/gitea-integration-mysql/data BUILTIN_SSH_SERVER_USER = git [attachment] -PATH = integrations/gitea-integration-mysql/data +STORE_TYPE = minio +MINIO_ENDPOINT = minio:9000 +MINIO_ACCESS_KEY_ID = 123456 +MINIO_SECRET_ACCESS_KEY = 123456 +MINIO_BUCKET = gitea +MINIO_LOCATION = us-east-1 +MINIO_BASE_PATH = attachments/ +MINIO_USE_SSL = false [mailer] ENABLED = true diff --git a/integrations/sqlite.ini.tmpl b/integrations/sqlite.ini.tmpl index ad79d2e8c5959..238d9a9c8a170 100644 --- a/integrations/sqlite.ini.tmpl +++ b/integrations/sqlite.ini.tmpl @@ -86,14 +86,4 @@ SECRET_KEY = 9pCviYTWSb INTERNAL_TOKEN = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0OTI3OTU5ODN9.OQkH5UmzID2XBdwQ9TAI6Jj2t1X-wElVTjbE7aoN4I8 [oauth2] -JWT_SECRET = KZb_QLUd4fYVyxetjxC4eZkrBgWM2SndOOWDNtgUUko - -[attachment] -STORE_TYPE = minio -MINIO_ENDPOINT = minio:9000 -MINIO_ACCESS_KEY_ID = 123456 -MINIO_SECRET_ACCESS_KEY = 123456 -MINIO_BUCKET = gitea -MINIO_LOCATION = us-east-1 -MINIO_BASE_PATH = attachments/ -MINIO_USE_SSL = false \ No newline at end of file +JWT_SECRET = KZb_QLUd4fYVyxetjxC4eZkrBgWM2SndOOWDNtgUUko \ No newline at end of file From a5b033c5ddaa09814f5d7496fce81fe7b8930879 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 23 Jun 2020 20:30:46 +0800 Subject: [PATCH 20/59] refactor the codes --- integrations/sqlite.ini.tmpl | 6 +-- models/attachment.go | 10 ++--- modules/setting/attachment.go | 72 +++++++++++++++++++++++++++++++++++ modules/setting/setting.go | 57 +-------------------------- 4 files changed, 81 insertions(+), 64 deletions(-) create mode 100644 modules/setting/attachment.go diff --git a/integrations/sqlite.ini.tmpl b/integrations/sqlite.ini.tmpl index 238d9a9c8a170..e899328c81fe9 100644 --- a/integrations/sqlite.ini.tmpl +++ b/integrations/sqlite.ini.tmpl @@ -66,12 +66,12 @@ PROVIDER = file PROVIDER_CONFIG = integrations/gitea-integration-sqlite/data/sessions [log] -MODE = test,file,console +MODE = test,file ROOT_PATH = sqlite-log REDIRECT_MACARON_LOG = true ROUTER = , MACARON = , -XORM = file,console +XORM = file [log.test] LEVEL = Info @@ -86,4 +86,4 @@ SECRET_KEY = 9pCviYTWSb INTERNAL_TOKEN = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0OTI3OTU5ODN9.OQkH5UmzID2XBdwQ9TAI6Jj2t1X-wElVTjbE7aoN4I8 [oauth2] -JWT_SECRET = KZb_QLUd4fYVyxetjxC4eZkrBgWM2SndOOWDNtgUUko \ No newline at end of file +JWT_SECRET = KZb_QLUd4fYVyxetjxC4eZkrBgWM2SndOOWDNtgUUko diff --git a/models/attachment.go b/models/attachment.go index 54cd562443e00..26f466a4008b9 100644 --- a/models/attachment.go +++ b/models/attachment.go @@ -56,11 +56,6 @@ func (a *Attachment) APIFormat() *api.Attachment { } } -// DownloadURL returns the download url of the attached file -func (a *Attachment) DownloadURL() string { - return fmt.Sprintf("%sattachments/%s", setting.AppURL, a.UUID) -} - // AttachmentRelativePath returns the relative path func AttachmentRelativePath(uuid string) string { return path.Join(uuid[0:1], uuid[1:2], uuid) @@ -71,6 +66,11 @@ func (a *Attachment) RelativePath() string { return AttachmentRelativePath(a.UUID) } +// DownloadURL returns the download url of the attached file +func (a *Attachment) DownloadURL() string { + return fmt.Sprintf("%sattachments/%s", setting.AppURL, a.UUID) +} + // LinkedRepository returns the linked repo if any func (a *Attachment) LinkedRepository() (*Repository, UnitType, error) { if a.IssueID != 0 { diff --git a/modules/setting/attachment.go b/modules/setting/attachment.go new file mode 100644 index 0000000000000..68530ab4d3829 --- /dev/null +++ b/modules/setting/attachment.go @@ -0,0 +1,72 @@ +// Copyright 2020 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package setting + +import ( + "path" + "path/filepath" + "strings" +) + +var ( + // Attachment settings + Attachment = struct { + StoreType string + Path string + Minio struct { + Endpoint string + AccessKeyID string + SecretAccessKey string + UseSSL bool + Bucket string + Location string + BasePath string + } + AllowedTypes string + MaxSize int64 + MaxFiles int + Enabled bool + }{ + StoreType: "local", + Minio: struct { + Endpoint string + AccessKeyID string + SecretAccessKey string + UseSSL bool + Bucket string + Location string + BasePath string + }{}, + AllowedTypes: "image/jpeg,image/png,application/zip,application/gzip", + MaxSize: 4, + MaxFiles: 5, + Enabled: true, + } +) + +func newAttachmentService() { + sec := Cfg.Section("attachment") + Attachment.StoreType = sec.Key("STORE_TYPE").MustString("local") + switch Attachment.StoreType { + case "local": + Attachment.Path = sec.Key("PATH").MustString(path.Join(AppDataPath, "attachments")) + if !filepath.IsAbs(Attachment.Path) { + Attachment.Path = path.Join(AppWorkPath, Attachment.Path) + } + case "minio": + Attachment.Minio.Endpoint = sec.Key("MINIO_ENDPOINT").MustString("localhost:9000") + Attachment.Minio.AccessKeyID = sec.Key("MINIO_ACCESS_KEY_ID").MustString("") + Attachment.Minio.SecretAccessKey = sec.Key("MINIO_SECRET_ACCESS_KEY").MustString("") + Attachment.Minio.Bucket = sec.Key("MINIO_BUCKET").MustString("gitea") + Attachment.Minio.Location = sec.Key("MINIO_LOCATION").MustString("us-east-1") + Attachment.Minio.BasePath = sec.Key("MINIO_BASE_PATH").MustString("attachments/") + Attachment.Minio.UseSSL = sec.Key("MINIO_USE_SSL").MustBool(false) + } + + Attachment.AllowedTypes = strings.Replace(sec.Key("ALLOWED_TYPES").MustString("image/jpeg,image/png,application/zip,application/gzip"), "|", ",", -1) + Attachment.MaxSize = sec.Key("MAX_SIZE").MustInt64(4) + Attachment.MaxFiles = sec.Key("MAX_FILES").MustInt(5) + Attachment.Enabled = sec.Key("ENABLED").MustBool(true) +} diff --git a/modules/setting/setting.go b/modules/setting/setting.go index bdb9db2103ae2..c4cbe1dd98b21 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -299,40 +299,6 @@ var ( AccessLogTemplate string EnableXORMLog bool - // Attachment settings - Attachment = struct { - StoreType string - Path string - Minio struct { - Endpoint string - AccessKeyID string - SecretAccessKey string - UseSSL bool - Bucket string - Location string - BasePath string - } - AllowedTypes string - MaxSize int64 - MaxFiles int - Enabled bool - }{ - StoreType: "local", - Minio: struct { - Endpoint string - AccessKeyID string - SecretAccessKey string - UseSSL bool - Bucket string - Location string - BasePath string - }{}, - AllowedTypes: "image/jpeg,image/png,application/zip,application/gzip", - MaxSize: 4, - MaxFiles: 5, - Enabled: true, - } - // Time settings TimeFormat string // UILocation is the location on the UI, so that we can display the time on UI. @@ -867,28 +833,7 @@ func NewContext() { } } - sec = Cfg.Section("attachment") - Attachment.StoreType = sec.Key("STORE_TYPE").MustString("local") - switch Attachment.StoreType { - case "local": - Attachment.Path = sec.Key("PATH").MustString(path.Join(AppDataPath, "attachments")) - if !filepath.IsAbs(Attachment.Path) { - Attachment.Path = path.Join(AppWorkPath, Attachment.Path) - } - case "minio": - Attachment.Minio.Endpoint = sec.Key("MINIO_ENDPOINT").MustString("localhost:9000") - Attachment.Minio.AccessKeyID = sec.Key("MINIO_ACCESS_KEY_ID").MustString("") - Attachment.Minio.SecretAccessKey = sec.Key("MINIO_SECRET_ACCESS_KEY").MustString("") - Attachment.Minio.Bucket = sec.Key("MINIO_BUCKET").MustString("gitea") - Attachment.Minio.Location = sec.Key("MINIO_LOCATION").MustString("us-east-1") - Attachment.Minio.BasePath = sec.Key("MINIO_BASE_PATH").MustString("attachments/") - Attachment.Minio.UseSSL = sec.Key("MINIO_USE_SSL").MustBool(false) - } - - Attachment.AllowedTypes = strings.Replace(sec.Key("ALLOWED_TYPES").MustString("image/jpeg,image/png,application/zip,application/gzip"), "|", ",", -1) - Attachment.MaxSize = sec.Key("MAX_SIZE").MustInt64(4) - Attachment.MaxFiles = sec.Key("MAX_FILES").MustInt(5) - Attachment.Enabled = sec.Key("ENABLED").MustBool(true) + newAttachmentService() timeFormatKey := Cfg.Section("time").Key("FORMAT").MustString("") if timeFormatKey != "" { From 669922a41a06d62a142a507d6e5b85867356806f Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 23 Jun 2020 22:14:13 +0800 Subject: [PATCH 21/59] add trace --- integrations/mysql.ini.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/integrations/mysql.ini.tmpl b/integrations/mysql.ini.tmpl index 57874f9354fbb..f43ae8f9a5c38 100644 --- a/integrations/mysql.ini.tmpl +++ b/integrations/mysql.ini.tmpl @@ -78,12 +78,12 @@ PROVIDER = file PROVIDER_CONFIG = integrations/gitea-integration-mysql/data/sessions [log] -MODE = test,file +MODE = test,file,console ROOT_PATH = mysql-log REDIRECT_MACARON_LOG = true ROUTER = , MACARON = , -XORM = file +XORM = file,console [log.test] LEVEL = Info From 80feb8ec8d4e15700d8ff7277e635995e1142320 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 23 Jun 2020 22:50:15 +0800 Subject: [PATCH 22/59] Fix test --- .drone.yml | 2 +- integrations/mysql.ini.tmpl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.drone.yml b/.drone.yml index ddcd582f400b8..0e05f166f8aaf 100644 --- a/.drone.yml +++ b/.drone.yml @@ -157,7 +157,7 @@ services: - minio server /data environment: MINIO_ACCESS_KEY: 123456 - MINIO_SECRET_KEY: 123456 + MINIO_SECRET_KEY: 12345678 steps: - name: fetch-tags diff --git a/integrations/mysql.ini.tmpl b/integrations/mysql.ini.tmpl index f43ae8f9a5c38..90365bd86aef9 100644 --- a/integrations/mysql.ini.tmpl +++ b/integrations/mysql.ini.tmpl @@ -45,7 +45,7 @@ BUILTIN_SSH_SERVER_USER = git STORE_TYPE = minio MINIO_ENDPOINT = minio:9000 MINIO_ACCESS_KEY_ID = 123456 -MINIO_SECRET_ACCESS_KEY = 123456 +MINIO_SECRET_ACCESS_KEY = 12345678 MINIO_BUCKET = gitea MINIO_LOCATION = us-east-1 MINIO_BASE_PATH = attachments/ From 76710e716ee72a4bec007bfd1ba6d19ee8688b01 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 24 Jun 2020 21:33:33 +0800 Subject: [PATCH 23/59] remove log on xorm --- integrations/mysql.ini.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integrations/mysql.ini.tmpl b/integrations/mysql.ini.tmpl index 90365bd86aef9..4aed280a28f24 100644 --- a/integrations/mysql.ini.tmpl +++ b/integrations/mysql.ini.tmpl @@ -83,7 +83,7 @@ ROOT_PATH = mysql-log REDIRECT_MACARON_LOG = true ROUTER = , MACARON = , -XORM = file,console +XORM = file [log.test] LEVEL = Info From afe4e8ad736ae9ee529be854918511480544d46a Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 26 Jun 2020 16:58:13 +0800 Subject: [PATCH 24/59] Fi download bug --- routers/repo/download.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/routers/repo/download.go b/routers/repo/download.go index 5ae9475ae7728..326f097cbcc08 100644 --- a/routers/repo/download.go +++ b/routers/repo/download.go @@ -22,7 +22,10 @@ import ( // ServeData download file from io.Reader func ServeData(ctx *context.Context, name string, reader io.Reader) error { buf := make([]byte, 1024) - n, _ := reader.Read(buf) + n, err := reader.Read(buf) + if err != nil && err != io.EOF { + return err + } if n >= 0 { buf = buf[:n] } @@ -48,7 +51,7 @@ func ServeData(ctx *context.Context, name string, reader io.Reader) error { ctx.Resp.Header().Set("Access-Control-Expose-Headers", "Content-Disposition") } - _, err := ctx.Resp.Write(buf) + _, err = ctx.Resp.Write(buf) if err != nil { return err } From fb0dd9e023b0927529606d76372c6d222373cf0a Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 12 May 2020 16:46:17 +0800 Subject: [PATCH 25/59] Add a storage layer for attachments --- go.sum | 2 -- modules/storage/local.go | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/go.sum b/go.sum index 33323ade3a459..cffd44e5274e6 100644 --- a/go.sum +++ b/go.sum @@ -760,8 +760,6 @@ github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1: github.com/yohcop/openid-go v1.0.0 h1:EciJ7ZLETHR3wOtxBvKXx9RV6eyHZpCaSZ1inbBaUXE= github.com/yohcop/openid-go v1.0.0/go.mod h1:/408xiwkeItSPJZSTPF7+VtZxPkPrRRpRNK2vjGh6yI= github.com/yuin/goldmark v1.1.7/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.22/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.25 h1:isv+Q6HQAmmL2Ofcmg8QauBmDPlUUnSoNhEcC940Rds= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1 h1:ruQGxdhGHe7FWOJPT0mKs5+pD2Xs1Bm/kdGlHO04FmM= diff --git a/modules/storage/local.go b/modules/storage/local.go index c570babec7a86..7a5f00e63685a 100644 --- a/modules/storage/local.go +++ b/modules/storage/local.go @@ -30,7 +30,7 @@ func NewLocalStorage(bucket string) (*LocalStorage, error) { }, nil } -// Open a file +// Open open a file func (l *LocalStorage) Open(path string) (io.ReadCloser, error) { f, err := os.Open(filepath.Join(l.dir, path)) if err != nil { @@ -39,7 +39,7 @@ func (l *LocalStorage) Open(path string) (io.ReadCloser, error) { return f, nil } -// Save a file +// Save save a file func (l *LocalStorage) Save(path string, r io.Reader) (int64, error) { p := filepath.Join(l.dir, path) if err := os.MkdirAll(filepath.Dir(p), os.ModePerm); err != nil { From 886a651b9b2b1dc14bd42c7c7fb721288196efc5 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 18 May 2020 00:26:45 +0800 Subject: [PATCH 26/59] Add setting for minio and flags for migrate-storage --- modules/storage/minio.go | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/storage/minio.go b/modules/storage/minio.go index e93416bf7bd76..46bac876c7394 100644 --- a/modules/storage/minio.go +++ b/modules/storage/minio.go @@ -20,6 +20,7 @@ var ( type MinioStorage struct { client *minio.Client bucket string + location string basePath string } From 457644a038f2f2bfd2dfb928c2112aa11f3e184f Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 18 May 2020 01:07:31 +0800 Subject: [PATCH 27/59] fix lint --- modules/storage/minio.go | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/storage/minio.go b/modules/storage/minio.go index 46bac876c7394..e93416bf7bd76 100644 --- a/modules/storage/minio.go +++ b/modules/storage/minio.go @@ -20,7 +20,6 @@ var ( type MinioStorage struct { client *minio.Client bucket string - location string basePath string } From 30f67cf6e4f66b75fc68cb72b83ef5e8eb48732a Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 18 May 2020 01:27:53 +0800 Subject: [PATCH 28/59] Add test for minio store type on attachments --- .drone.yml | 8 ++++++++ integrations/sqlite.ini.tmpl | 10 ++++++++++ 2 files changed, 18 insertions(+) diff --git a/.drone.yml b/.drone.yml index 0e05f166f8aaf..986eddf667131 100644 --- a/.drone.yml +++ b/.drone.yml @@ -150,6 +150,14 @@ services: environment: discovery.type: single-node image: elasticsearch:7.5.0 + + - name: minio + image: minio/minio:RELEASE.2020-05-16T01-33-21Z + commands: + - minio server ./data + environment: + MINIO_ACCESS_KEY: 123456 + MINIO_SECRET_KEY: 123456 - name: minio image: minio/minio:RELEASE.2020-05-16T01-33-21Z diff --git a/integrations/sqlite.ini.tmpl b/integrations/sqlite.ini.tmpl index e899328c81fe9..5bec06ee84aed 100644 --- a/integrations/sqlite.ini.tmpl +++ b/integrations/sqlite.ini.tmpl @@ -87,3 +87,13 @@ INTERNAL_TOKEN = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0OTI3OTU5ODN9.O [oauth2] JWT_SECRET = KZb_QLUd4fYVyxetjxC4eZkrBgWM2SndOOWDNtgUUko + +[attachment] +STORE_TYPE = minio +MINIO_ENDPOINT = localhost:9000 +MINIO_ACCESS_KEY_ID = 123456 +MINIO_SECRET_ACCESS_KEY = 123456 +MINIO_BUCKET = gitea +MINIO_LOCATION = us-east-1 +MINIO_BASE_PATH = attachments/ +MINIO_USE_SSL = false \ No newline at end of file From 3507a2c97773cb32c00bf14716e6aaebdf859673 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 20 May 2020 15:06:25 +0800 Subject: [PATCH 29/59] Apply suggestions from code review Co-authored-by: guillep2k <18600385+guillep2k@users.noreply.github.com> --- modules/storage/local.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/storage/local.go b/modules/storage/local.go index 7a5f00e63685a..c570babec7a86 100644 --- a/modules/storage/local.go +++ b/modules/storage/local.go @@ -30,7 +30,7 @@ func NewLocalStorage(bucket string) (*LocalStorage, error) { }, nil } -// Open open a file +// Open a file func (l *LocalStorage) Open(path string) (io.ReadCloser, error) { f, err := os.Open(filepath.Join(l.dir, path)) if err != nil { @@ -39,7 +39,7 @@ func (l *LocalStorage) Open(path string) (io.ReadCloser, error) { return f, nil } -// Save save a file +// Save a file func (l *LocalStorage) Save(path string, r io.Reader) (int64, error) { p := filepath.Join(l.dir, path) if err := os.MkdirAll(filepath.Dir(p), os.ModePerm); err != nil { From ac20111c85b216488167c7eb1446e8b4d94e46de Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 3 Jun 2020 00:12:50 +0800 Subject: [PATCH 30/59] Fix drone --- .drone.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.drone.yml b/.drone.yml index 986eddf667131..d297d62a3fe9a 100644 --- a/.drone.yml +++ b/.drone.yml @@ -150,14 +150,6 @@ services: environment: discovery.type: single-node image: elasticsearch:7.5.0 - - - name: minio - image: minio/minio:RELEASE.2020-05-16T01-33-21Z - commands: - - minio server ./data - environment: - MINIO_ACCESS_KEY: 123456 - MINIO_SECRET_KEY: 123456 - name: minio image: minio/minio:RELEASE.2020-05-16T01-33-21Z @@ -312,6 +304,14 @@ services: pull: default image: gitea/test-openldap:latest + - name: minio + image: minio/minio:RELEASE.2020-05-16T01-33-21Z + commands: + - minio server ./data + environment: + MINIO_ACCESS_KEY: 123456 + MINIO_SECRET_KEY: 123456 + steps: - name: fetch-tags pull: default From 0b43483c94bc26e0f555413c9df918629b8c6113 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 8 Jun 2020 20:24:14 +0800 Subject: [PATCH 31/59] fix test --- integrations/sqlite.ini.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integrations/sqlite.ini.tmpl b/integrations/sqlite.ini.tmpl index 5bec06ee84aed..db171c2eecef6 100644 --- a/integrations/sqlite.ini.tmpl +++ b/integrations/sqlite.ini.tmpl @@ -90,7 +90,7 @@ JWT_SECRET = KZb_QLUd4fYVyxetjxC4eZkrBgWM2SndOOWDNtgUUko [attachment] STORE_TYPE = minio -MINIO_ENDPOINT = localhost:9000 +MINIO_ENDPOINT = minio:9000 MINIO_ACCESS_KEY_ID = 123456 MINIO_SECRET_ACCESS_KEY = 123456 MINIO_BUCKET = gitea From fa8776d44f57d82d41f7639defad762a0b0f493f Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 21 Jun 2020 21:00:08 +0800 Subject: [PATCH 32/59] Fix test --- .drone.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index d297d62a3fe9a..86e529b490aa1 100644 --- a/.drone.yml +++ b/.drone.yml @@ -307,7 +307,7 @@ services: - name: minio image: minio/minio:RELEASE.2020-05-16T01-33-21Z commands: - - minio server ./data + - minio server /data environment: MINIO_ACCESS_KEY: 123456 MINIO_SECRET_KEY: 123456 From 418153cebc8575d2135ecf2ed4e66944e6a7d3cf Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 22 Jun 2020 21:01:24 +0800 Subject: [PATCH 33/59] display the error on console --- integrations/sqlite.ini.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/integrations/sqlite.ini.tmpl b/integrations/sqlite.ini.tmpl index db171c2eecef6..ad79d2e8c5959 100644 --- a/integrations/sqlite.ini.tmpl +++ b/integrations/sqlite.ini.tmpl @@ -66,12 +66,12 @@ PROVIDER = file PROVIDER_CONFIG = integrations/gitea-integration-sqlite/data/sessions [log] -MODE = test,file +MODE = test,file,console ROOT_PATH = sqlite-log REDIRECT_MACARON_LOG = true ROUTER = , MACARON = , -XORM = file +XORM = file,console [log.test] LEVEL = Info From d306cbe2f481a937b626f27c492382a3795e8b71 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 23 Jun 2020 20:12:20 +0800 Subject: [PATCH 34/59] Move minio test to amd64 since minio docker don't support arm64 --- .drone.yml | 12 ++++-------- integrations/mysql.ini.tmpl | 4 ++++ integrations/sqlite.ini.tmpl | 12 +----------- 3 files changed, 9 insertions(+), 19 deletions(-) diff --git a/.drone.yml b/.drone.yml index 86e529b490aa1..e4fe13e93021f 100644 --- a/.drone.yml +++ b/.drone.yml @@ -157,7 +157,11 @@ services: - minio server /data environment: MINIO_ACCESS_KEY: 123456 +<<<<<<< HEAD MINIO_SECRET_KEY: 12345678 +======= + MINIO_SECRET_KEY: 123456 +>>>>>>> Move minio test to amd64 since minio docker don't support arm64 steps: - name: fetch-tags @@ -304,14 +308,6 @@ services: pull: default image: gitea/test-openldap:latest - - name: minio - image: minio/minio:RELEASE.2020-05-16T01-33-21Z - commands: - - minio server /data - environment: - MINIO_ACCESS_KEY: 123456 - MINIO_SECRET_KEY: 123456 - steps: - name: fetch-tags pull: default diff --git a/integrations/mysql.ini.tmpl b/integrations/mysql.ini.tmpl index 4aed280a28f24..75738c4e8c9b0 100644 --- a/integrations/mysql.ini.tmpl +++ b/integrations/mysql.ini.tmpl @@ -45,7 +45,11 @@ BUILTIN_SSH_SERVER_USER = git STORE_TYPE = minio MINIO_ENDPOINT = minio:9000 MINIO_ACCESS_KEY_ID = 123456 +<<<<<<< HEAD MINIO_SECRET_ACCESS_KEY = 12345678 +======= +MINIO_SECRET_ACCESS_KEY = 123456 +>>>>>>> Move minio test to amd64 since minio docker don't support arm64 MINIO_BUCKET = gitea MINIO_LOCATION = us-east-1 MINIO_BASE_PATH = attachments/ diff --git a/integrations/sqlite.ini.tmpl b/integrations/sqlite.ini.tmpl index ad79d2e8c5959..238d9a9c8a170 100644 --- a/integrations/sqlite.ini.tmpl +++ b/integrations/sqlite.ini.tmpl @@ -86,14 +86,4 @@ SECRET_KEY = 9pCviYTWSb INTERNAL_TOKEN = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0OTI3OTU5ODN9.OQkH5UmzID2XBdwQ9TAI6Jj2t1X-wElVTjbE7aoN4I8 [oauth2] -JWT_SECRET = KZb_QLUd4fYVyxetjxC4eZkrBgWM2SndOOWDNtgUUko - -[attachment] -STORE_TYPE = minio -MINIO_ENDPOINT = minio:9000 -MINIO_ACCESS_KEY_ID = 123456 -MINIO_SECRET_ACCESS_KEY = 123456 -MINIO_BUCKET = gitea -MINIO_LOCATION = us-east-1 -MINIO_BASE_PATH = attachments/ -MINIO_USE_SSL = false \ No newline at end of file +JWT_SECRET = KZb_QLUd4fYVyxetjxC4eZkrBgWM2SndOOWDNtgUUko \ No newline at end of file From d9ca0d41ac43d0dc6d5aa60556374d36be263c3e Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 23 Jun 2020 20:30:46 +0800 Subject: [PATCH 35/59] refactor the codes --- integrations/sqlite.ini.tmpl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/integrations/sqlite.ini.tmpl b/integrations/sqlite.ini.tmpl index 238d9a9c8a170..e899328c81fe9 100644 --- a/integrations/sqlite.ini.tmpl +++ b/integrations/sqlite.ini.tmpl @@ -66,12 +66,12 @@ PROVIDER = file PROVIDER_CONFIG = integrations/gitea-integration-sqlite/data/sessions [log] -MODE = test,file,console +MODE = test,file ROOT_PATH = sqlite-log REDIRECT_MACARON_LOG = true ROUTER = , MACARON = , -XORM = file,console +XORM = file [log.test] LEVEL = Info @@ -86,4 +86,4 @@ SECRET_KEY = 9pCviYTWSb INTERNAL_TOKEN = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0OTI3OTU5ODN9.OQkH5UmzID2XBdwQ9TAI6Jj2t1X-wElVTjbE7aoN4I8 [oauth2] -JWT_SECRET = KZb_QLUd4fYVyxetjxC4eZkrBgWM2SndOOWDNtgUUko \ No newline at end of file +JWT_SECRET = KZb_QLUd4fYVyxetjxC4eZkrBgWM2SndOOWDNtgUUko From a097ad8a4ded4d5971137f6ba92822f9743fe73a Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 23 Jun 2020 22:14:13 +0800 Subject: [PATCH 36/59] add trace --- integrations/mysql.ini.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integrations/mysql.ini.tmpl b/integrations/mysql.ini.tmpl index 75738c4e8c9b0..cbb14fee8a94c 100644 --- a/integrations/mysql.ini.tmpl +++ b/integrations/mysql.ini.tmpl @@ -87,7 +87,7 @@ ROOT_PATH = mysql-log REDIRECT_MACARON_LOG = true ROUTER = , MACARON = , -XORM = file +XORM = file,console [log.test] LEVEL = Info From 4c40fc6dd97c27b4099d056e608b1ab328e7b7ff Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 23 Jun 2020 22:50:15 +0800 Subject: [PATCH 37/59] Fix test --- .drone.yml | 4 ---- integrations/mysql.ini.tmpl | 4 ---- 2 files changed, 8 deletions(-) diff --git a/.drone.yml b/.drone.yml index e4fe13e93021f..0e05f166f8aaf 100644 --- a/.drone.yml +++ b/.drone.yml @@ -157,11 +157,7 @@ services: - minio server /data environment: MINIO_ACCESS_KEY: 123456 -<<<<<<< HEAD MINIO_SECRET_KEY: 12345678 -======= - MINIO_SECRET_KEY: 123456 ->>>>>>> Move minio test to amd64 since minio docker don't support arm64 steps: - name: fetch-tags diff --git a/integrations/mysql.ini.tmpl b/integrations/mysql.ini.tmpl index cbb14fee8a94c..90365bd86aef9 100644 --- a/integrations/mysql.ini.tmpl +++ b/integrations/mysql.ini.tmpl @@ -45,11 +45,7 @@ BUILTIN_SSH_SERVER_USER = git STORE_TYPE = minio MINIO_ENDPOINT = minio:9000 MINIO_ACCESS_KEY_ID = 123456 -<<<<<<< HEAD MINIO_SECRET_ACCESS_KEY = 12345678 -======= -MINIO_SECRET_ACCESS_KEY = 123456 ->>>>>>> Move minio test to amd64 since minio docker don't support arm64 MINIO_BUCKET = gitea MINIO_LOCATION = us-east-1 MINIO_BASE_PATH = attachments/ From d54bed633e0283ca65551a31a588917e09af7ef8 Mon Sep 17 00:00:00 2001 From: Tyler Date: Wed, 24 Jun 2020 22:55:33 -0400 Subject: [PATCH 38/59] Add URL function to serve attachments directly from S3/Minio --- modules/storage/local.go | 6 ++++++ modules/storage/minio.go | 16 +++++++++++++--- modules/storage/storage.go | 7 +++++++ routers/repo/attachment.go | 13 +++++++++++++ 4 files changed, 39 insertions(+), 3 deletions(-) diff --git a/modules/storage/local.go b/modules/storage/local.go index c570babec7a86..dd873d69512be 100644 --- a/modules/storage/local.go +++ b/modules/storage/local.go @@ -6,6 +6,7 @@ package storage import ( "io" + "net/url" "os" "path/filepath" ) @@ -64,3 +65,8 @@ func (l *LocalStorage) Delete(path string) error { p := filepath.Join(l.dir, path) return os.Remove(p) } + +// URL gets the redirect URL to a file +func (l *LocalStorage) URL(path, name string) (*url.URL, error) { + return nil, ErrUrlNotSupported +} diff --git a/modules/storage/minio.go b/modules/storage/minio.go index e93416bf7bd76..c9046dfe0da29 100644 --- a/modules/storage/minio.go +++ b/modules/storage/minio.go @@ -5,15 +5,17 @@ package storage import ( + "github.com/minio/minio-go" "io" + "net/url" "path" "strings" - - "github.com/minio/minio-go" + "time" ) var ( - _ ObjectStorage = &MinioStorage{} + _ ObjectStorage = &MinioStorage{} + quoteEscaper = strings.NewReplacer("\\", "\\\\", `"`, "\\\"") ) // MinioStorage returns a minio bucket storage @@ -68,3 +70,11 @@ func (m *MinioStorage) Save(path string, r io.Reader) (int64, error) { func (m *MinioStorage) Delete(path string) error { return m.client.RemoveObject(m.bucket, m.buildMinioPath(path)) } + +// URL gets the redirect URL to a file. The presigned link is valid for 5 minutes. +func (m *MinioStorage) URL(path, name string) (*url.URL, error) { + reqParams := make(url.Values) + // TODO it may be good to embed images with 'inline' like ServeData does, but we don't want to have to read the file, do we? + reqParams.Set("response-content-disposition", "attachment; filename=\""+quoteEscaper.Replace(name)+"\"") + return m.client.PresignedGetObject(m.bucket, m.buildMinioPath(path), 5*time.Minute, reqParams) +} diff --git a/modules/storage/storage.go b/modules/storage/storage.go index 963b38d0fdbb2..378ac7e27f108 100644 --- a/modules/storage/storage.go +++ b/modules/storage/storage.go @@ -5,17 +5,24 @@ package storage import ( + "errors" "fmt" "io" + "net/url" "code.gitea.io/gitea/modules/setting" ) +var ( + ErrUrlNotSupported = errors.New("url method not supported") +) + // ObjectStorage represents an object storage to handle a bucket and files type ObjectStorage interface { Save(path string, r io.Reader) (int64, error) Open(path string) (io.ReadCloser, error) Delete(path string) error + URL(path, name string) (*url.URL, error) } // Copy copys a file from source ObjectStorage to dest ObjectStorage diff --git a/routers/repo/attachment.go b/routers/repo/attachment.go index 479e8b3951bea..d98da6a183d7f 100644 --- a/routers/repo/attachment.go +++ b/routers/repo/attachment.go @@ -123,6 +123,19 @@ func GetAttachment(ctx *context.Context) { } } + //If we have a signed url (S3, object storage), redirect to this directly. + u, err := storage.Attachments.URL(attach.RelativePath(), attach.Name) + + if u != nil && err == nil { + if err := attach.IncreaseDownloadCount(); err != nil { + ctx.ServerError("Update", err) + return + } + + ctx.Redirect(u.String()) + return + } + //If we have matched and access to release or issue fr, err := storage.Attachments.Open(attach.RelativePath()) if err != nil { From f6b74a7f9547edff10a72cd8ba25ce4ae28b4959 Mon Sep 17 00:00:00 2001 From: Tyler Date: Wed, 24 Jun 2020 23:24:56 -0400 Subject: [PATCH 39/59] Add ability to enable/disable redirection in attachment configuration --- custom/conf/app.example.ini | 9 ++++++--- .../doc/advanced/config-cheat-sheet.en-us.md | 1 + integrations/mysql.ini.tmpl | 1 + modules/setting/attachment.go | 11 +++++++---- routers/repo/attachment.go | 18 ++++++++++-------- 5 files changed, 25 insertions(+), 15 deletions(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 38b501f339df8..bbd3b5bc3652e 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -756,17 +756,20 @@ ALLOWED_TYPES = image/jpeg|image/png|application/zip|application/gzip MAX_SIZE = 4 ; Max number of files per upload. Defaults to 5 MAX_FILES = 5 -; Storage type for attachments, `local` for local disk or `minio` for s3 compatible +; Storage type for attachments, `local` for local disk or `minio` for s3 compatible ; object storage service, default is `local`. STORE_TYPE = local +; Allows the storage driver to redirect to authenticated URLs to serve files directly +; Currently, only `minio` is supported. +SERVE_DIRECT = false ; Path for attachments. Defaults to `data/attachments` only available when STORE_TYPE is `local` PATH = data/attachments ; Minio endpoint to connect only available when STORE_TYPE is `minio` MINIO_ENDPOINT = localhost:9000 ; Minio accessKeyID to connect only available when STORE_TYPE is `minio` -MINIO_ACCESS_KEY_ID = +MINIO_ACCESS_KEY_ID = ; Minio secretAccessKey to connect only available when STORE_TYPE is `minio` -MINIO_SECRET_ACCESS_KEY = +MINIO_SECRET_ACCESS_KEY = ; Minio bucket to store the attachments only available when STORE_TYPE is `minio` MINIO_BUCKET = gitea ; Minio location to create bucket only available when STORE_TYPE is `minio` diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 2556fcd091d63..9e3ef3fa4faf2 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -475,6 +475,7 @@ set name for unique queues. Individual queues will default to - `MAX_SIZE`: **4**: Maximum size (MB). - `MAX_FILES`: **5**: Maximum number of attachments that can be uploaded at once. - `STORE_TYPE`: **local**: Storage type for attachments, `local` for local disk or `minio` for s3 compatible object storage service, default is `local`. +- `SERVE_DIRECT`: **false**: Allows the storage driver to redirect to authenticated URLs to serve files directly. Currently, only Minio/S3 is supported via signed URLs, local dcoes nothing. - `PATH`: **data/attachments**: Path to store attachments only available when STORE_TYPE is `local` - `MINIO_ENDPOINT`: **localhost:9000**: Minio endpoint to connect only available when STORE_TYPE is `minio` - `MINIO_ACCESS_KEY_ID`: Minio accessKeyID to connect only available when STORE_TYPE is `minio` diff --git a/integrations/mysql.ini.tmpl b/integrations/mysql.ini.tmpl index 90365bd86aef9..ae87a6cab25f3 100644 --- a/integrations/mysql.ini.tmpl +++ b/integrations/mysql.ini.tmpl @@ -43,6 +43,7 @@ BUILTIN_SSH_SERVER_USER = git [attachment] STORE_TYPE = minio +SERVE_DIRECT = false MINIO_ENDPOINT = minio:9000 MINIO_ACCESS_KEY_ID = 123456 MINIO_SECRET_ACCESS_KEY = 12345678 diff --git a/modules/setting/attachment.go b/modules/setting/attachment.go index 68530ab4d3829..4c7368eb68b7d 100644 --- a/modules/setting/attachment.go +++ b/modules/setting/attachment.go @@ -13,9 +13,10 @@ import ( var ( // Attachment settings Attachment = struct { - StoreType string - Path string - Minio struct { + StoreType string + Path string + ServeDirect bool + Minio struct { Endpoint string AccessKeyID string SecretAccessKey string @@ -29,7 +30,8 @@ var ( MaxFiles int Enabled bool }{ - StoreType: "local", + StoreType: "local", + ServeDirect: false, Minio: struct { Endpoint string AccessKeyID string @@ -49,6 +51,7 @@ var ( func newAttachmentService() { sec := Cfg.Section("attachment") Attachment.StoreType = sec.Key("STORE_TYPE").MustString("local") + Attachment.ServeDirect = sec.Key("SERVE_DIRECT").MustBool(false) switch Attachment.StoreType { case "local": Attachment.Path = sec.Key("PATH").MustString(path.Join(AppDataPath, "attachments")) diff --git a/routers/repo/attachment.go b/routers/repo/attachment.go index d98da6a183d7f..d3201faec0f60 100644 --- a/routers/repo/attachment.go +++ b/routers/repo/attachment.go @@ -123,17 +123,19 @@ func GetAttachment(ctx *context.Context) { } } - //If we have a signed url (S3, object storage), redirect to this directly. - u, err := storage.Attachments.URL(attach.RelativePath(), attach.Name) + if setting.Attachment.ServeDirect { + //If we have a signed url (S3, object storage), redirect to this directly. + u, err := storage.Attachments.URL(attach.RelativePath(), attach.Name) - if u != nil && err == nil { - if err := attach.IncreaseDownloadCount(); err != nil { - ctx.ServerError("Update", err) + if u != nil && err == nil { + if err := attach.IncreaseDownloadCount(); err != nil { + ctx.ServerError("Update", err) + return + } + + ctx.Redirect(u.String()) return } - - ctx.Redirect(u.String()) - return } //If we have matched and access to release or issue From 21802ea4f258d98876aca7c33057253b2320f3b0 Mon Sep 17 00:00:00 2001 From: Tyler Date: Wed, 24 Jun 2020 23:29:46 -0400 Subject: [PATCH 40/59] Fix typo --- docs/content/doc/advanced/config-cheat-sheet.en-us.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 9e3ef3fa4faf2..2bf825123522f 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -475,7 +475,7 @@ set name for unique queues. Individual queues will default to - `MAX_SIZE`: **4**: Maximum size (MB). - `MAX_FILES`: **5**: Maximum number of attachments that can be uploaded at once. - `STORE_TYPE`: **local**: Storage type for attachments, `local` for local disk or `minio` for s3 compatible object storage service, default is `local`. -- `SERVE_DIRECT`: **false**: Allows the storage driver to redirect to authenticated URLs to serve files directly. Currently, only Minio/S3 is supported via signed URLs, local dcoes nothing. +- `SERVE_DIRECT`: **false**: Allows the storage driver to redirect to authenticated URLs to serve files directly. Currently, only Minio/S3 is supported via signed URLs, local does nothing. - `PATH`: **data/attachments**: Path to store attachments only available when STORE_TYPE is `local` - `MINIO_ENDPOINT`: **localhost:9000**: Minio endpoint to connect only available when STORE_TYPE is `minio` - `MINIO_ACCESS_KEY_ID`: Minio accessKeyID to connect only available when STORE_TYPE is `minio` From b58df9e05348e26ffb5d2832a71b5eaf3929f1a2 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 12 May 2020 16:46:17 +0800 Subject: [PATCH 41/59] Add a storage layer for attachments --- modules/storage/local.go | 4 ++-- modules/storage/minio.go | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/storage/local.go b/modules/storage/local.go index dd873d69512be..51e034e79eb5e 100644 --- a/modules/storage/local.go +++ b/modules/storage/local.go @@ -31,7 +31,7 @@ func NewLocalStorage(bucket string) (*LocalStorage, error) { }, nil } -// Open a file +// Open open a file func (l *LocalStorage) Open(path string) (io.ReadCloser, error) { f, err := os.Open(filepath.Join(l.dir, path)) if err != nil { @@ -40,7 +40,7 @@ func (l *LocalStorage) Open(path string) (io.ReadCloser, error) { return f, nil } -// Save a file +// Save save a file func (l *LocalStorage) Save(path string, r io.Reader) (int64, error) { p := filepath.Join(l.dir, path) if err := os.MkdirAll(filepath.Dir(p), os.ModePerm); err != nil { diff --git a/modules/storage/minio.go b/modules/storage/minio.go index c9046dfe0da29..65a34bcfac0f2 100644 --- a/modules/storage/minio.go +++ b/modules/storage/minio.go @@ -5,12 +5,13 @@ package storage import ( - "github.com/minio/minio-go" "io" "net/url" "path" "strings" "time" + + "github.com/minio/minio-go" ) var ( From c8f33160f9a89636c38d9e35ea606a50b6a79133 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 18 May 2020 00:26:45 +0800 Subject: [PATCH 42/59] Add setting for minio and flags for migrate-storage --- modules/storage/minio.go | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/storage/minio.go b/modules/storage/minio.go index 65a34bcfac0f2..018068fbaf5a0 100644 --- a/modules/storage/minio.go +++ b/modules/storage/minio.go @@ -23,6 +23,7 @@ var ( type MinioStorage struct { client *minio.Client bucket string + location string basePath string } From 751d721b240b3ace68be935f5dba678c06e1c2e6 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 18 May 2020 01:07:31 +0800 Subject: [PATCH 43/59] fix lint --- modules/storage/minio.go | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/storage/minio.go b/modules/storage/minio.go index 018068fbaf5a0..65a34bcfac0f2 100644 --- a/modules/storage/minio.go +++ b/modules/storage/minio.go @@ -23,7 +23,6 @@ var ( type MinioStorage struct { client *minio.Client bucket string - location string basePath string } From 4be66c5496e693cdb122b9029b7e2598b9c9137e Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 18 May 2020 01:27:53 +0800 Subject: [PATCH 44/59] Add test for minio store type on attachments --- .drone.yml | 8 ++++++++ integrations/sqlite.ini.tmpl | 10 ++++++++++ 2 files changed, 18 insertions(+) diff --git a/.drone.yml b/.drone.yml index 0e05f166f8aaf..986eddf667131 100644 --- a/.drone.yml +++ b/.drone.yml @@ -150,6 +150,14 @@ services: environment: discovery.type: single-node image: elasticsearch:7.5.0 + + - name: minio + image: minio/minio:RELEASE.2020-05-16T01-33-21Z + commands: + - minio server ./data + environment: + MINIO_ACCESS_KEY: 123456 + MINIO_SECRET_KEY: 123456 - name: minio image: minio/minio:RELEASE.2020-05-16T01-33-21Z diff --git a/integrations/sqlite.ini.tmpl b/integrations/sqlite.ini.tmpl index e899328c81fe9..5bec06ee84aed 100644 --- a/integrations/sqlite.ini.tmpl +++ b/integrations/sqlite.ini.tmpl @@ -87,3 +87,13 @@ INTERNAL_TOKEN = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0OTI3OTU5ODN9.O [oauth2] JWT_SECRET = KZb_QLUd4fYVyxetjxC4eZkrBgWM2SndOOWDNtgUUko + +[attachment] +STORE_TYPE = minio +MINIO_ENDPOINT = localhost:9000 +MINIO_ACCESS_KEY_ID = 123456 +MINIO_SECRET_ACCESS_KEY = 123456 +MINIO_BUCKET = gitea +MINIO_LOCATION = us-east-1 +MINIO_BASE_PATH = attachments/ +MINIO_USE_SSL = false \ No newline at end of file From ffa008c74372ba2de7076725c201992558e59eb3 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 20 May 2020 15:06:25 +0800 Subject: [PATCH 45/59] Apply suggestions from code review Co-authored-by: guillep2k <18600385+guillep2k@users.noreply.github.com> --- modules/storage/local.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/storage/local.go b/modules/storage/local.go index 51e034e79eb5e..dd873d69512be 100644 --- a/modules/storage/local.go +++ b/modules/storage/local.go @@ -31,7 +31,7 @@ func NewLocalStorage(bucket string) (*LocalStorage, error) { }, nil } -// Open open a file +// Open a file func (l *LocalStorage) Open(path string) (io.ReadCloser, error) { f, err := os.Open(filepath.Join(l.dir, path)) if err != nil { @@ -40,7 +40,7 @@ func (l *LocalStorage) Open(path string) (io.ReadCloser, error) { return f, nil } -// Save save a file +// Save a file func (l *LocalStorage) Save(path string, r io.Reader) (int64, error) { p := filepath.Join(l.dir, path) if err := os.MkdirAll(filepath.Dir(p), os.ModePerm); err != nil { From 23091b46e69dacdbc797cd436b1e3e3bafcf75be Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 3 Jun 2020 00:12:50 +0800 Subject: [PATCH 46/59] Fix drone --- .drone.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.drone.yml b/.drone.yml index 986eddf667131..d297d62a3fe9a 100644 --- a/.drone.yml +++ b/.drone.yml @@ -150,14 +150,6 @@ services: environment: discovery.type: single-node image: elasticsearch:7.5.0 - - - name: minio - image: minio/minio:RELEASE.2020-05-16T01-33-21Z - commands: - - minio server ./data - environment: - MINIO_ACCESS_KEY: 123456 - MINIO_SECRET_KEY: 123456 - name: minio image: minio/minio:RELEASE.2020-05-16T01-33-21Z @@ -312,6 +304,14 @@ services: pull: default image: gitea/test-openldap:latest + - name: minio + image: minio/minio:RELEASE.2020-05-16T01-33-21Z + commands: + - minio server ./data + environment: + MINIO_ACCESS_KEY: 123456 + MINIO_SECRET_KEY: 123456 + steps: - name: fetch-tags pull: default From 64eddce067a1b97bdc4d27f593773a8aac7c77ca Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 8 Jun 2020 20:24:14 +0800 Subject: [PATCH 47/59] fix test --- integrations/sqlite.ini.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integrations/sqlite.ini.tmpl b/integrations/sqlite.ini.tmpl index 5bec06ee84aed..db171c2eecef6 100644 --- a/integrations/sqlite.ini.tmpl +++ b/integrations/sqlite.ini.tmpl @@ -90,7 +90,7 @@ JWT_SECRET = KZb_QLUd4fYVyxetjxC4eZkrBgWM2SndOOWDNtgUUko [attachment] STORE_TYPE = minio -MINIO_ENDPOINT = localhost:9000 +MINIO_ENDPOINT = minio:9000 MINIO_ACCESS_KEY_ID = 123456 MINIO_SECRET_ACCESS_KEY = 123456 MINIO_BUCKET = gitea From e650f3294edfa2fcb31e774fb2503a790620f79b Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 21 Jun 2020 21:00:08 +0800 Subject: [PATCH 48/59] Fix test --- .drone.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index d297d62a3fe9a..86e529b490aa1 100644 --- a/.drone.yml +++ b/.drone.yml @@ -307,7 +307,7 @@ services: - name: minio image: minio/minio:RELEASE.2020-05-16T01-33-21Z commands: - - minio server ./data + - minio server /data environment: MINIO_ACCESS_KEY: 123456 MINIO_SECRET_KEY: 123456 From bdca7b01e66cdde6abed4dfd7bd2a7fb01e59319 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 22 Jun 2020 21:01:24 +0800 Subject: [PATCH 49/59] display the error on console --- integrations/sqlite.ini.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/integrations/sqlite.ini.tmpl b/integrations/sqlite.ini.tmpl index db171c2eecef6..ad79d2e8c5959 100644 --- a/integrations/sqlite.ini.tmpl +++ b/integrations/sqlite.ini.tmpl @@ -66,12 +66,12 @@ PROVIDER = file PROVIDER_CONFIG = integrations/gitea-integration-sqlite/data/sessions [log] -MODE = test,file +MODE = test,file,console ROOT_PATH = sqlite-log REDIRECT_MACARON_LOG = true ROUTER = , MACARON = , -XORM = file +XORM = file,console [log.test] LEVEL = Info From 0f9d767363096904bcaaa4acd05643c3ec5b11a0 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 23 Jun 2020 20:12:20 +0800 Subject: [PATCH 50/59] Move minio test to amd64 since minio docker don't support arm64 --- .drone.yml | 8 -------- integrations/sqlite.ini.tmpl | 12 +----------- 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/.drone.yml b/.drone.yml index 86e529b490aa1..0e05f166f8aaf 100644 --- a/.drone.yml +++ b/.drone.yml @@ -304,14 +304,6 @@ services: pull: default image: gitea/test-openldap:latest - - name: minio - image: minio/minio:RELEASE.2020-05-16T01-33-21Z - commands: - - minio server /data - environment: - MINIO_ACCESS_KEY: 123456 - MINIO_SECRET_KEY: 123456 - steps: - name: fetch-tags pull: default diff --git a/integrations/sqlite.ini.tmpl b/integrations/sqlite.ini.tmpl index ad79d2e8c5959..238d9a9c8a170 100644 --- a/integrations/sqlite.ini.tmpl +++ b/integrations/sqlite.ini.tmpl @@ -86,14 +86,4 @@ SECRET_KEY = 9pCviYTWSb INTERNAL_TOKEN = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0OTI3OTU5ODN9.OQkH5UmzID2XBdwQ9TAI6Jj2t1X-wElVTjbE7aoN4I8 [oauth2] -JWT_SECRET = KZb_QLUd4fYVyxetjxC4eZkrBgWM2SndOOWDNtgUUko - -[attachment] -STORE_TYPE = minio -MINIO_ENDPOINT = minio:9000 -MINIO_ACCESS_KEY_ID = 123456 -MINIO_SECRET_ACCESS_KEY = 123456 -MINIO_BUCKET = gitea -MINIO_LOCATION = us-east-1 -MINIO_BASE_PATH = attachments/ -MINIO_USE_SSL = false \ No newline at end of file +JWT_SECRET = KZb_QLUd4fYVyxetjxC4eZkrBgWM2SndOOWDNtgUUko \ No newline at end of file From d2974c0ba7f1da996082f4a4235f04dccaf8152e Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 26 Jun 2020 17:57:51 +0800 Subject: [PATCH 51/59] don't change unrelated files --- integrations/mysql.ini.tmpl | 4 ++-- integrations/sqlite.ini.tmpl | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/integrations/mysql.ini.tmpl b/integrations/mysql.ini.tmpl index ae87a6cab25f3..5691311660c89 100644 --- a/integrations/mysql.ini.tmpl +++ b/integrations/mysql.ini.tmpl @@ -79,12 +79,12 @@ PROVIDER = file PROVIDER_CONFIG = integrations/gitea-integration-mysql/data/sessions [log] -MODE = test,file,console +MODE = test,file ROOT_PATH = mysql-log REDIRECT_MACARON_LOG = true ROUTER = , MACARON = , -XORM = file,console +XORM = file [log.test] LEVEL = Info diff --git a/integrations/sqlite.ini.tmpl b/integrations/sqlite.ini.tmpl index 238d9a9c8a170..e899328c81fe9 100644 --- a/integrations/sqlite.ini.tmpl +++ b/integrations/sqlite.ini.tmpl @@ -66,12 +66,12 @@ PROVIDER = file PROVIDER_CONFIG = integrations/gitea-integration-sqlite/data/sessions [log] -MODE = test,file,console +MODE = test,file ROOT_PATH = sqlite-log REDIRECT_MACARON_LOG = true ROUTER = , MACARON = , -XORM = file,console +XORM = file [log.test] LEVEL = Info @@ -86,4 +86,4 @@ SECRET_KEY = 9pCviYTWSb INTERNAL_TOKEN = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0OTI3OTU5ODN9.OQkH5UmzID2XBdwQ9TAI6Jj2t1X-wElVTjbE7aoN4I8 [oauth2] -JWT_SECRET = KZb_QLUd4fYVyxetjxC4eZkrBgWM2SndOOWDNtgUUko \ No newline at end of file +JWT_SECRET = KZb_QLUd4fYVyxetjxC4eZkrBgWM2SndOOWDNtgUUko From d3e2973a53a7ec58ffd8778ff7b882e8ab6c5412 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 26 Jun 2020 17:58:40 +0800 Subject: [PATCH 52/59] Fix lint --- modules/storage/storage.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/storage/storage.go b/modules/storage/storage.go index 378ac7e27f108..ffc73d294afdf 100644 --- a/modules/storage/storage.go +++ b/modules/storage/storage.go @@ -14,7 +14,8 @@ import ( ) var ( - ErrUrlNotSupported = errors.New("url method not supported") + // ErrURLNotSupported represents url is not supported + ErrURLNotSupported = errors.New("url method not supported") ) // ObjectStorage represents an object storage to handle a bucket and files From b9998cfb00f2a7a082d9e22393f3076bec06c2ac Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 26 Jun 2020 18:07:33 +0800 Subject: [PATCH 53/59] Fix build --- modules/storage/local.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/storage/local.go b/modules/storage/local.go index dd873d69512be..456090989599f 100644 --- a/modules/storage/local.go +++ b/modules/storage/local.go @@ -68,5 +68,5 @@ func (l *LocalStorage) Delete(path string) error { // URL gets the redirect URL to a file func (l *LocalStorage) URL(path, name string) (*url.URL, error) { - return nil, ErrUrlNotSupported + return nil, ErrURLNotSupported } From 8f43baf2ed6e89ecf551cb93afc895edd108931e Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 2 Jul 2020 11:12:35 +0800 Subject: [PATCH 54/59] update go.mod and go.sum --- go.sum | 1 + 1 file changed, 1 insertion(+) diff --git a/go.sum b/go.sum index cffd44e5274e6..a93bc0ba0326f 100644 --- a/go.sum +++ b/go.sum @@ -760,6 +760,7 @@ github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1: github.com/yohcop/openid-go v1.0.0 h1:EciJ7ZLETHR3wOtxBvKXx9RV6eyHZpCaSZ1inbBaUXE= github.com/yohcop/openid-go v1.0.0/go.mod h1:/408xiwkeItSPJZSTPF7+VtZxPkPrRRpRNK2vjGh6yI= github.com/yuin/goldmark v1.1.7/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.22/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1 h1:ruQGxdhGHe7FWOJPT0mKs5+pD2Xs1Bm/kdGlHO04FmM= From 3dffb03d75f32ef43956a5ad596db166cf350772 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 2 Jul 2020 11:21:58 +0800 Subject: [PATCH 55/59] Use github.com/minio/minio-go/v6 --- go.mod | 3 +- go.sum | 18 +- modules/storage/minio.go | 2 +- vendor/github.com/go-ini/ini/.gitignore | 6 - vendor/github.com/go-ini/ini/LICENSE | 191 --- vendor/github.com/go-ini/ini/Makefile | 15 - vendor/github.com/go-ini/ini/README.md | 43 - vendor/github.com/go-ini/ini/codecov.yml | 9 - vendor/github.com/go-ini/ini/data_source.go | 76 - vendor/github.com/go-ini/ini/deprecated.go | 25 - vendor/github.com/go-ini/ini/error.go | 34 - vendor/github.com/go-ini/ini/file.go | 509 ------ vendor/github.com/go-ini/ini/helper.go | 24 - vendor/github.com/go-ini/ini/ini.go | 168 -- vendor/github.com/go-ini/ini/key.go | 829 ---------- vendor/github.com/go-ini/ini/parser.go | 535 ------ vendor/github.com/go-ini/ini/section.go | 256 --- vendor/github.com/go-ini/ini/struct.go | 729 --------- .../github.com/json-iterator/go/.codecov.yml | 3 + vendor/github.com/json-iterator/go/.gitignore | 4 + .../github.com/json-iterator/go/.travis.yml | 14 + vendor/github.com/json-iterator/go/Gopkg.lock | 21 + vendor/github.com/json-iterator/go/Gopkg.toml | 26 + vendor/github.com/json-iterator/go/LICENSE | 21 + vendor/github.com/json-iterator/go/README.md | 87 + vendor/github.com/json-iterator/go/adapter.go | 150 ++ vendor/github.com/json-iterator/go/any.go | 325 ++++ .../github.com/json-iterator/go/any_array.go | 278 ++++ .../github.com/json-iterator/go/any_bool.go | 137 ++ .../github.com/json-iterator/go/any_float.go | 83 + .../github.com/json-iterator/go/any_int32.go | 74 + .../github.com/json-iterator/go/any_int64.go | 74 + .../json-iterator/go/any_invalid.go | 82 + vendor/github.com/json-iterator/go/any_nil.go | 69 + .../github.com/json-iterator/go/any_number.go | 123 ++ .../github.com/json-iterator/go/any_object.go | 374 +++++ vendor/github.com/json-iterator/go/any_str.go | 166 ++ .../github.com/json-iterator/go/any_uint32.go | 74 + .../github.com/json-iterator/go/any_uint64.go | 74 + vendor/github.com/json-iterator/go/build.sh | 12 + vendor/github.com/json-iterator/go/config.go | 375 +++++ .../go/fuzzy_mode_convert_table.md | 7 + vendor/github.com/json-iterator/go/go.mod | 11 + vendor/github.com/json-iterator/go/go.sum | 14 + vendor/github.com/json-iterator/go/iter.go | 349 ++++ .../github.com/json-iterator/go/iter_array.go | 64 + .../github.com/json-iterator/go/iter_float.go | 339 ++++ .../github.com/json-iterator/go/iter_int.go | 345 ++++ .../json-iterator/go/iter_object.go | 267 +++ .../github.com/json-iterator/go/iter_skip.go | 130 ++ .../json-iterator/go/iter_skip_sloppy.go | 163 ++ .../json-iterator/go/iter_skip_strict.go | 99 ++ .../github.com/json-iterator/go/iter_str.go | 215 +++ .../github.com/json-iterator/go/jsoniter.go | 18 + vendor/github.com/json-iterator/go/pool.go | 42 + vendor/github.com/json-iterator/go/reflect.go | 337 ++++ .../json-iterator/go/reflect_array.go | 104 ++ .../json-iterator/go/reflect_dynamic.go | 70 + .../json-iterator/go/reflect_extension.go | 483 ++++++ .../json-iterator/go/reflect_json_number.go | 112 ++ .../go/reflect_json_raw_message.go | 60 + .../json-iterator/go/reflect_map.go | 346 ++++ .../json-iterator/go/reflect_marshaler.go | 225 +++ .../json-iterator/go/reflect_native.go | 453 ++++++ .../json-iterator/go/reflect_optional.go | 133 ++ .../json-iterator/go/reflect_slice.go | 99 ++ .../go/reflect_struct_decoder.go | 1092 +++++++++++++ .../go/reflect_struct_encoder.go | 211 +++ vendor/github.com/json-iterator/go/stream.go | 211 +++ .../json-iterator/go/stream_float.go | 111 ++ .../github.com/json-iterator/go/stream_int.go | 190 +++ .../github.com/json-iterator/go/stream_str.go | 372 +++++ vendor/github.com/json-iterator/go/test.sh | 12 + vendor/github.com/klauspost/cpuid/.gitignore | 24 + vendor/github.com/klauspost/cpuid/.travis.yml | 23 + .../klauspost/cpuid/CONTRIBUTING.txt | 35 + vendor/github.com/klauspost/cpuid/LICENSE | 22 + vendor/github.com/klauspost/cpuid/README.md | 157 ++ vendor/github.com/klauspost/cpuid/cpuid.go | 1184 ++++++++++++++ vendor/github.com/klauspost/cpuid/cpuid_386.s | 42 + .../github.com/klauspost/cpuid/cpuid_amd64.s | 42 + .../klauspost/cpuid/detect_intel.go | 17 + .../github.com/klauspost/cpuid/detect_ref.go | 23 + vendor/github.com/klauspost/cpuid/generate.go | 4 + .../minio/{minio-go => md5-simd}/LICENSE | 0 vendor/github.com/minio/md5-simd/README.md | 196 +++ .../minio/md5-simd/block-generic.go | 132 ++ .../github.com/minio/md5-simd/block16_amd64.s | 227 +++ .../github.com/minio/md5-simd/block8_amd64.s | 279 ++++ .../github.com/minio/md5-simd/block_amd64.go | 199 +++ vendor/github.com/minio/md5-simd/go.mod | 7 + vendor/github.com/minio/md5-simd/go.sum | 2 + .../minio/md5-simd/md5-digest_amd64.go | 178 ++ .../minio/md5-simd/md5-server_amd64.go | 307 ++++ .../minio/md5-simd/md5-server_fallback.go | 12 + .../minio/md5-simd/md5-util_amd64.go | 70 + vendor/github.com/minio/md5-simd/md5.go | 57 + vendor/github.com/minio/minio-go/.travis.yml | 28 - vendor/github.com/minio/minio-go/Makefile | 15 - vendor/github.com/minio/minio-go/NOTICE | 2 - .../minio/minio-go/api-put-bucket.go | 306 ---- vendor/github.com/minio/minio-go/api-stat.go | 185 --- vendor/github.com/minio/minio-go/transport.go | 50 - .../minio/minio-go/{ => v6}/.gitignore | 1 + .../minio/minio-go/v6/.golangci.yml | 16 + .../minio/minio-go/{ => v6}/CONTRIBUTING.md | 0 vendor/github.com/minio/minio-go/v6/LICENSE | 202 +++ .../minio/minio-go/{ => v6}/MAINTAINERS.md | 6 +- vendor/github.com/minio/minio-go/v6/Makefile | 26 + vendor/github.com/minio/minio-go/v6/NOTICE | 2 + .../minio/minio-go/{ => v6}/README.md | 114 +- .../minio/minio-go/{ => v6}/README_zh_CN.md | 107 +- .../minio/minio-go/v6/api-bucket-tagging.go | 147 ++ .../minio-go/{ => v6}/api-compose-object.go | 117 +- .../minio/minio-go/{ => v6}/api-datatypes.go | 53 +- .../minio-go/{ => v6}/api-error-response.go | 10 +- .../minio-go/v6/api-get-bucket-encryption.go | 71 + .../minio-go/v6/api-get-bucket-versioning.go | 78 + .../minio-go/{ => v6}/api-get-lifecycle.go | 6 +- .../api-get-object-acl-context.go} | 18 +- .../minio/minio-go/v6/api-get-object-acl.go | 27 + .../{ => v6}/api-get-object-context.go | 4 +- .../minio-go/{ => v6}/api-get-object-file.go | 20 +- .../minio/minio-go/{ => v6}/api-get-object.go | 91 +- .../minio-go/{ => v6}/api-get-options.go | 6 +- .../minio/minio-go/{ => v6}/api-get-policy.go | 6 +- .../minio/minio-go/{ => v6}/api-list.go | 232 ++- .../minio-go/{ => v6}/api-notification.go | 91 +- .../minio-go/v6/api-object-legal-hold.go | 176 ++ .../minio/minio-go/v6/api-object-lock.go | 241 +++ .../minio/minio-go/v6/api-object-retention.go | 168 ++ .../minio/minio-go/v6/api-object-tagging.go | 154 ++ .../minio/minio-go/{ => v6}/api-presigned.go | 14 +- .../minio/minio-go/v6/api-put-bucket.go | 537 ++++++ .../{ => v6}/api-put-object-common.go | 89 +- .../{ => v6}/api-put-object-context.go | 4 +- .../minio-go/{ => v6}/api-put-object-copy.go | 26 +- .../{ => v6}/api-put-object-file-context.go | 6 +- .../minio-go/{ => v6}/api-put-object-file.go | 4 +- .../{ => v6}/api-put-object-multipart.go | 27 +- .../{ => v6}/api-put-object-streaming.go | 134 +- .../minio/minio-go/{ => v6}/api-put-object.go | 130 +- .../minio/minio-go/{ => v6}/api-remove.go | 193 ++- .../minio-go/{ => v6}/api-s3-datatypes.go | 4 +- .../minio/minio-go/{ => v6}/api-select.go | 255 ++- .../github.com/minio/minio-go/v6/api-stat.go | 110 ++ .../github.com/minio/minio-go/{ => v6}/api.go | 233 ++- .../minio/minio-go/{ => v6}/bucket-cache.go | 57 +- .../minio-go/{ => v6}/bucket-notification.go | 120 +- .../minio/minio-go/{ => v6}/constants.go | 30 +- .../minio/minio-go/{ => v6}/core.go | 110 +- vendor/github.com/minio/minio-go/v6/go.mod | 16 + vendor/github.com/minio/minio-go/v6/go.sum | 57 + .../minio/minio-go/{ => v6}/hook-reader.go | 24 +- .../v6/pkg/credentials/assume_role.go | 214 +++ .../{ => v6}/pkg/credentials/chain.go | 4 +- .../pkg/credentials/config.json.sample | 2 +- .../{ => v6}/pkg/credentials/credentials.go | 4 +- .../pkg/credentials/credentials.sample | 0 .../minio-go/{ => v6}/pkg/credentials/doc.go | 4 +- .../{ => v6}/pkg/credentials/env_aws.go | 4 +- .../{ => v6}/pkg/credentials/env_minio.go | 4 +- .../pkg/credentials/file_aws_credentials.go | 32 +- .../pkg/credentials/file_minio_client.go | 36 +- .../{ => v6}/pkg/credentials/iam_aws.go | 112 +- .../pkg/credentials/signature-type.go | 4 +- .../{ => v6}/pkg/credentials/static.go | 4 +- .../pkg/credentials/sts_client_grants.go | 33 +- .../v6/pkg/credentials/sts_ldap_identity.go | 119 ++ .../pkg/credentials/sts_web_identity.go | 55 +- .../{ => v6}/pkg/encrypt/server-side.go | 11 +- .../minio-go/{ => v6}/pkg/s3utils/utils.go | 76 +- .../minio-go/{ => v6}/pkg/set/stringset.go | 9 +- .../signer}/request-signature-streaming.go | 20 +- .../pkg/signer}/request-signature-v2.go | 8 +- .../pkg/signer}/request-signature-v4.go | 103 +- .../{pkg/s3signer => v6/pkg/signer}/utils.go | 18 +- .../minio/minio-go/v6/pkg/tags/tags.go | 330 ++++ .../minio/minio-go/{ => v6}/post-policy.go | 31 +- .../minio-go/{ => v6}/retry-continous.go | 4 +- .../minio/minio-go/{ => v6}/retry.go | 53 +- .../minio/minio-go/{ => v6}/s3-endpoints.go | 9 +- .../minio/minio-go/{ => v6}/s3-error.go | 4 +- .../minio/minio-go/v6/staticcheck.conf | 1 + .../github.com/minio/minio-go/v6/transport.go | 83 + .../minio/minio-go/{ => v6}/utils.go | 187 ++- .../github.com/minio/sha256-simd/.gitignore | 1 + .../github.com/minio/sha256-simd/.travis.yml | 25 + vendor/github.com/minio/sha256-simd/LICENSE | 202 +++ vendor/github.com/minio/sha256-simd/README.md | 133 ++ .../{minio-go => sha256-simd}/appveyor.yml | 19 +- vendor/github.com/minio/sha256-simd/cpuid.go | 119 ++ .../github.com/minio/sha256-simd/cpuid_386.go | 24 + .../github.com/minio/sha256-simd/cpuid_386.s | 53 + .../minio/sha256-simd/cpuid_amd64.go | 24 + .../minio/sha256-simd/cpuid_amd64.s | 53 + .../github.com/minio/sha256-simd/cpuid_arm.go | 32 + .../minio/sha256-simd/cpuid_linux_arm64.go | 49 + .../minio/sha256-simd/cpuid_other.go | 34 + vendor/github.com/minio/sha256-simd/go.mod | 3 + vendor/github.com/minio/sha256-simd/sha256.go | 409 +++++ .../sha256-simd/sha256blockAvx2_amd64.go | 22 + .../minio/sha256-simd/sha256blockAvx2_amd64.s | 1449 +++++++++++++++++ .../sha256-simd/sha256blockAvx512_amd64.asm | 686 ++++++++ .../sha256-simd/sha256blockAvx512_amd64.go | 500 ++++++ .../sha256-simd/sha256blockAvx512_amd64.s | 267 +++ .../minio/sha256-simd/sha256blockAvx_amd64.go | 22 + .../minio/sha256-simd/sha256blockAvx_amd64.s | 408 +++++ .../minio/sha256-simd/sha256blockSha_amd64.go | 6 + .../minio/sha256-simd/sha256blockSha_amd64.s | 266 +++ .../sha256-simd/sha256blockSsse_amd64.go | 22 + .../minio/sha256-simd/sha256blockSsse_amd64.s | 429 +++++ .../minio/sha256-simd/sha256block_amd64.go | 53 + .../minio/sha256-simd/sha256block_arm64.go | 37 + .../minio/sha256-simd/sha256block_arm64.s | 192 +++ .../minio/sha256-simd/sha256block_other.go | 25 + .../minio/sha256-simd/test-architectures.sh | 15 + .../modern-go/concurrent/.gitignore | 1 + .../modern-go/concurrent/.travis.yml | 14 + .../github.com/modern-go/concurrent/LICENSE | 201 +++ .../github.com/modern-go/concurrent/README.md | 49 + .../modern-go/concurrent/executor.go | 14 + .../modern-go/concurrent/go_above_19.go | 15 + .../modern-go/concurrent/go_below_19.go | 33 + vendor/github.com/modern-go/concurrent/log.go | 13 + .../github.com/modern-go/concurrent/test.sh | 12 + .../concurrent/unbounded_executor.go | 119 ++ .../github.com/modern-go/reflect2/.gitignore | 2 + .../github.com/modern-go/reflect2/.travis.yml | 15 + .../github.com/modern-go/reflect2/Gopkg.lock | 15 + .../github.com/modern-go/reflect2/Gopkg.toml | 35 + vendor/github.com/modern-go/reflect2/LICENSE | 201 +++ .../github.com/modern-go/reflect2/README.md | 71 + .../modern-go/reflect2/go_above_17.go | 8 + .../modern-go/reflect2/go_above_19.go | 14 + .../modern-go/reflect2/go_below_17.go | 9 + .../modern-go/reflect2/go_below_19.go | 14 + .../github.com/modern-go/reflect2/reflect2.go | 298 ++++ .../modern-go/reflect2/reflect2_amd64.s | 0 .../modern-go/reflect2/reflect2_kind.go | 30 + .../modern-go/reflect2/relfect2_386.s | 0 .../modern-go/reflect2/relfect2_amd64p32.s | 0 .../modern-go/reflect2/relfect2_arm.s | 0 .../modern-go/reflect2/relfect2_arm64.s | 0 .../modern-go/reflect2/relfect2_mips64x.s | 0 .../modern-go/reflect2/relfect2_mipsx.s | 0 .../modern-go/reflect2/relfect2_ppc64x.s | 0 .../modern-go/reflect2/relfect2_s390x.s | 0 .../modern-go/reflect2/safe_field.go | 58 + .../github.com/modern-go/reflect2/safe_map.go | 101 ++ .../modern-go/reflect2/safe_slice.go | 92 ++ .../modern-go/reflect2/safe_struct.go | 29 + .../modern-go/reflect2/safe_type.go | 78 + vendor/github.com/modern-go/reflect2/test.sh | 12 + .../github.com/modern-go/reflect2/type_map.go | 113 ++ .../modern-go/reflect2/unsafe_array.go | 65 + .../modern-go/reflect2/unsafe_eface.go | 59 + .../modern-go/reflect2/unsafe_field.go | 74 + .../modern-go/reflect2/unsafe_iface.go | 64 + .../modern-go/reflect2/unsafe_link.go | 70 + .../modern-go/reflect2/unsafe_map.go | 138 ++ .../modern-go/reflect2/unsafe_ptr.go | 46 + .../modern-go/reflect2/unsafe_slice.go | 177 ++ .../modern-go/reflect2/unsafe_struct.go | 59 + .../modern-go/reflect2/unsafe_type.go | 85 + vendor/modules.txt | 32 +- 266 files changed, 25685 insertions(+), 5004 deletions(-) delete mode 100644 vendor/github.com/go-ini/ini/.gitignore delete mode 100644 vendor/github.com/go-ini/ini/LICENSE delete mode 100644 vendor/github.com/go-ini/ini/Makefile delete mode 100644 vendor/github.com/go-ini/ini/README.md delete mode 100644 vendor/github.com/go-ini/ini/codecov.yml delete mode 100644 vendor/github.com/go-ini/ini/data_source.go delete mode 100644 vendor/github.com/go-ini/ini/deprecated.go delete mode 100644 vendor/github.com/go-ini/ini/error.go delete mode 100644 vendor/github.com/go-ini/ini/file.go delete mode 100644 vendor/github.com/go-ini/ini/helper.go delete mode 100644 vendor/github.com/go-ini/ini/ini.go delete mode 100644 vendor/github.com/go-ini/ini/key.go delete mode 100644 vendor/github.com/go-ini/ini/parser.go delete mode 100644 vendor/github.com/go-ini/ini/section.go delete mode 100644 vendor/github.com/go-ini/ini/struct.go create mode 100644 vendor/github.com/json-iterator/go/.codecov.yml create mode 100644 vendor/github.com/json-iterator/go/.gitignore create mode 100644 vendor/github.com/json-iterator/go/.travis.yml create mode 100644 vendor/github.com/json-iterator/go/Gopkg.lock create mode 100644 vendor/github.com/json-iterator/go/Gopkg.toml create mode 100644 vendor/github.com/json-iterator/go/LICENSE create mode 100644 vendor/github.com/json-iterator/go/README.md create mode 100644 vendor/github.com/json-iterator/go/adapter.go create mode 100644 vendor/github.com/json-iterator/go/any.go create mode 100644 vendor/github.com/json-iterator/go/any_array.go create mode 100644 vendor/github.com/json-iterator/go/any_bool.go create mode 100644 vendor/github.com/json-iterator/go/any_float.go create mode 100644 vendor/github.com/json-iterator/go/any_int32.go create mode 100644 vendor/github.com/json-iterator/go/any_int64.go create mode 100644 vendor/github.com/json-iterator/go/any_invalid.go create mode 100644 vendor/github.com/json-iterator/go/any_nil.go create mode 100644 vendor/github.com/json-iterator/go/any_number.go create mode 100644 vendor/github.com/json-iterator/go/any_object.go create mode 100644 vendor/github.com/json-iterator/go/any_str.go create mode 100644 vendor/github.com/json-iterator/go/any_uint32.go create mode 100644 vendor/github.com/json-iterator/go/any_uint64.go create mode 100644 vendor/github.com/json-iterator/go/build.sh create mode 100644 vendor/github.com/json-iterator/go/config.go create mode 100644 vendor/github.com/json-iterator/go/fuzzy_mode_convert_table.md create mode 100644 vendor/github.com/json-iterator/go/go.mod create mode 100644 vendor/github.com/json-iterator/go/go.sum create mode 100644 vendor/github.com/json-iterator/go/iter.go create mode 100644 vendor/github.com/json-iterator/go/iter_array.go create mode 100644 vendor/github.com/json-iterator/go/iter_float.go create mode 100644 vendor/github.com/json-iterator/go/iter_int.go create mode 100644 vendor/github.com/json-iterator/go/iter_object.go create mode 100644 vendor/github.com/json-iterator/go/iter_skip.go create mode 100644 vendor/github.com/json-iterator/go/iter_skip_sloppy.go create mode 100644 vendor/github.com/json-iterator/go/iter_skip_strict.go create mode 100644 vendor/github.com/json-iterator/go/iter_str.go create mode 100644 vendor/github.com/json-iterator/go/jsoniter.go create mode 100644 vendor/github.com/json-iterator/go/pool.go create mode 100644 vendor/github.com/json-iterator/go/reflect.go create mode 100644 vendor/github.com/json-iterator/go/reflect_array.go create mode 100644 vendor/github.com/json-iterator/go/reflect_dynamic.go create mode 100644 vendor/github.com/json-iterator/go/reflect_extension.go create mode 100644 vendor/github.com/json-iterator/go/reflect_json_number.go create mode 100644 vendor/github.com/json-iterator/go/reflect_json_raw_message.go create mode 100644 vendor/github.com/json-iterator/go/reflect_map.go create mode 100644 vendor/github.com/json-iterator/go/reflect_marshaler.go create mode 100644 vendor/github.com/json-iterator/go/reflect_native.go create mode 100644 vendor/github.com/json-iterator/go/reflect_optional.go create mode 100644 vendor/github.com/json-iterator/go/reflect_slice.go create mode 100644 vendor/github.com/json-iterator/go/reflect_struct_decoder.go create mode 100644 vendor/github.com/json-iterator/go/reflect_struct_encoder.go create mode 100644 vendor/github.com/json-iterator/go/stream.go create mode 100644 vendor/github.com/json-iterator/go/stream_float.go create mode 100644 vendor/github.com/json-iterator/go/stream_int.go create mode 100644 vendor/github.com/json-iterator/go/stream_str.go create mode 100644 vendor/github.com/json-iterator/go/test.sh create mode 100644 vendor/github.com/klauspost/cpuid/.gitignore create mode 100644 vendor/github.com/klauspost/cpuid/.travis.yml create mode 100644 vendor/github.com/klauspost/cpuid/CONTRIBUTING.txt create mode 100644 vendor/github.com/klauspost/cpuid/LICENSE create mode 100644 vendor/github.com/klauspost/cpuid/README.md create mode 100644 vendor/github.com/klauspost/cpuid/cpuid.go create mode 100644 vendor/github.com/klauspost/cpuid/cpuid_386.s create mode 100644 vendor/github.com/klauspost/cpuid/cpuid_amd64.s create mode 100644 vendor/github.com/klauspost/cpuid/detect_intel.go create mode 100644 vendor/github.com/klauspost/cpuid/detect_ref.go create mode 100644 vendor/github.com/klauspost/cpuid/generate.go rename vendor/github.com/minio/{minio-go => md5-simd}/LICENSE (100%) create mode 100644 vendor/github.com/minio/md5-simd/README.md create mode 100644 vendor/github.com/minio/md5-simd/block-generic.go create mode 100644 vendor/github.com/minio/md5-simd/block16_amd64.s create mode 100644 vendor/github.com/minio/md5-simd/block8_amd64.s create mode 100644 vendor/github.com/minio/md5-simd/block_amd64.go create mode 100644 vendor/github.com/minio/md5-simd/go.mod create mode 100644 vendor/github.com/minio/md5-simd/go.sum create mode 100644 vendor/github.com/minio/md5-simd/md5-digest_amd64.go create mode 100644 vendor/github.com/minio/md5-simd/md5-server_amd64.go create mode 100644 vendor/github.com/minio/md5-simd/md5-server_fallback.go create mode 100644 vendor/github.com/minio/md5-simd/md5-util_amd64.go create mode 100644 vendor/github.com/minio/md5-simd/md5.go delete mode 100644 vendor/github.com/minio/minio-go/.travis.yml delete mode 100644 vendor/github.com/minio/minio-go/Makefile delete mode 100644 vendor/github.com/minio/minio-go/NOTICE delete mode 100644 vendor/github.com/minio/minio-go/api-put-bucket.go delete mode 100644 vendor/github.com/minio/minio-go/api-stat.go delete mode 100644 vendor/github.com/minio/minio-go/transport.go rename vendor/github.com/minio/minio-go/{ => v6}/.gitignore (60%) create mode 100644 vendor/github.com/minio/minio-go/v6/.golangci.yml rename vendor/github.com/minio/minio-go/{ => v6}/CONTRIBUTING.md (100%) create mode 100644 vendor/github.com/minio/minio-go/v6/LICENSE rename vendor/github.com/minio/minio-go/{ => v6}/MAINTAINERS.md (71%) create mode 100644 vendor/github.com/minio/minio-go/v6/Makefile create mode 100644 vendor/github.com/minio/minio-go/v6/NOTICE rename vendor/github.com/minio/minio-go/{ => v6}/README.md (58%) rename vendor/github.com/minio/minio-go/{ => v6}/README_zh_CN.md (59%) create mode 100644 vendor/github.com/minio/minio-go/v6/api-bucket-tagging.go rename vendor/github.com/minio/minio-go/{ => v6}/api-compose-object.go (85%) rename vendor/github.com/minio/minio-go/{ => v6}/api-datatypes.go (61%) rename vendor/github.com/minio/minio-go/{ => v6}/api-error-response.go (96%) create mode 100644 vendor/github.com/minio/minio-go/v6/api-get-bucket-encryption.go create mode 100644 vendor/github.com/minio/minio-go/v6/api-get-bucket-versioning.go rename vendor/github.com/minio/minio-go/{ => v6}/api-get-lifecycle.go (93%) rename vendor/github.com/minio/minio-go/{api-get-object-acl.go => v6/api-get-object-acl-context.go} (86%) create mode 100644 vendor/github.com/minio/minio-go/v6/api-get-object-acl.go rename vendor/github.com/minio/minio-go/{ => v6}/api-get-object-context.go (91%) rename vendor/github.com/minio/minio-go/{ => v6}/api-get-object-file.go (85%) rename vendor/github.com/minio/minio-go/{ => v6}/api-get-object.go (90%) rename vendor/github.com/minio/minio-go/{ => v6}/api-get-options.go (96%) rename vendor/github.com/minio/minio-go/{ => v6}/api-get-policy.go (93%) rename vendor/github.com/minio/minio-go/{ => v6}/api-list.go (77%) rename vendor/github.com/minio/minio-go/{ => v6}/api-notification.go (75%) create mode 100644 vendor/github.com/minio/minio-go/v6/api-object-legal-hold.go create mode 100644 vendor/github.com/minio/minio-go/v6/api-object-lock.go create mode 100644 vendor/github.com/minio/minio-go/v6/api-object-retention.go create mode 100644 vendor/github.com/minio/minio-go/v6/api-object-tagging.go rename vendor/github.com/minio/minio-go/{ => v6}/api-presigned.go (93%) create mode 100644 vendor/github.com/minio/minio-go/v6/api-put-bucket.go rename vendor/github.com/minio/minio-go/{ => v6}/api-put-object-common.go (54%) rename vendor/github.com/minio/minio-go/{ => v6}/api-put-object-context.go (92%) rename vendor/github.com/minio/minio-go/{ => v6}/api-put-object-copy.go (72%) rename vendor/github.com/minio/minio-go/{ => v6}/api-put-object-file-context.go (93%) rename vendor/github.com/minio/minio-go/{ => v6}/api-put-object-file.go (90%) rename vendor/github.com/minio/minio-go/{ => v6}/api-put-object-multipart.go (94%) rename vendor/github.com/minio/minio-go/{ => v6}/api-put-object-streaming.go (78%) rename vendor/github.com/minio/minio-go/{ => v6}/api-put-object.go (68%) rename vendor/github.com/minio/minio-go/{ => v6}/api-remove.go (61%) rename vendor/github.com/minio/minio-go/{ => v6}/api-s3-datatypes.go (98%) rename vendor/github.com/minio/minio-go/{ => v6}/api-select.go (65%) create mode 100644 vendor/github.com/minio/minio-go/v6/api-stat.go rename vendor/github.com/minio/minio-go/{ => v6}/api.go (79%) rename vendor/github.com/minio/minio-go/{ => v6}/bucket-cache.go (78%) rename vendor/github.com/minio/minio-go/{ => v6}/bucket-notification.go (69%) rename vendor/github.com/minio/minio-go/{ => v6}/constants.go (68%) rename vendor/github.com/minio/minio-go/{ => v6}/core.go (52%) create mode 100644 vendor/github.com/minio/minio-go/v6/go.mod create mode 100644 vendor/github.com/minio/minio-go/v6/go.sum rename vendor/github.com/minio/minio-go/{ => v6}/hook-reader.go (83%) create mode 100644 vendor/github.com/minio/minio-go/v6/pkg/credentials/assume_role.go rename vendor/github.com/minio/minio-go/{ => v6}/pkg/credentials/chain.go (96%) rename vendor/github.com/minio/minio-go/{ => v6}/pkg/credentials/config.json.sample (87%) rename vendor/github.com/minio/minio-go/{ => v6}/pkg/credentials/credentials.go (98%) rename vendor/github.com/minio/minio-go/{ => v6}/pkg/credentials/credentials.sample (100%) rename vendor/github.com/minio/minio-go/{ => v6}/pkg/credentials/doc.go (96%) rename vendor/github.com/minio/minio-go/{ => v6}/pkg/credentials/env_aws.go (95%) rename vendor/github.com/minio/minio-go/{ => v6}/pkg/credentials/env_minio.go (94%) rename vendor/github.com/minio/minio-go/{ => v6}/pkg/credentials/file_aws_credentials.go (85%) rename vendor/github.com/minio/minio-go/{ => v6}/pkg/credentials/file_minio_client.go (83%) rename vendor/github.com/minio/minio-go/{ => v6}/pkg/credentials/iam_aws.go (74%) rename vendor/github.com/minio/minio-go/{ => v6}/pkg/credentials/signature-type.go (95%) rename vendor/github.com/minio/minio-go/{ => v6}/pkg/credentials/static.go (95%) rename vendor/github.com/minio/minio-go/{ => v6}/pkg/credentials/sts_client_grants.go (87%) create mode 100644 vendor/github.com/minio/minio-go/v6/pkg/credentials/sts_ldap_identity.go rename vendor/github.com/minio/minio-go/{ => v6}/pkg/credentials/sts_web_identity.go (81%) rename vendor/github.com/minio/minio-go/{ => v6}/pkg/encrypt/server-side.go (96%) rename vendor/github.com/minio/minio-go/{ => v6}/pkg/s3utils/utils.go (81%) rename vendor/github.com/minio/minio-go/{ => v6}/pkg/set/stringset.go (96%) rename vendor/github.com/minio/minio-go/{pkg/s3signer => v6/pkg/signer}/request-signature-streaming.go (95%) rename vendor/github.com/minio/minio-go/{pkg/s3signer => v6/pkg/signer}/request-signature-v2.go (98%) rename vendor/github.com/minio/minio-go/{pkg/s3signer => v6/pkg/signer}/request-signature-v4.go (77%) rename vendor/github.com/minio/minio-go/{pkg/s3signer => v6/pkg/signer}/utils.go (69%) create mode 100644 vendor/github.com/minio/minio-go/v6/pkg/tags/tags.go rename vendor/github.com/minio/minio-go/{ => v6}/post-policy.go (88%) rename vendor/github.com/minio/minio-go/{ => v6}/retry-continous.go (95%) rename vendor/github.com/minio/minio-go/{ => v6}/retry.go (69%) rename vendor/github.com/minio/minio-go/{ => v6}/s3-endpoints.go (84%) rename vendor/github.com/minio/minio-go/{ => v6}/s3-error.go (97%) create mode 100644 vendor/github.com/minio/minio-go/v6/staticcheck.conf create mode 100644 vendor/github.com/minio/minio-go/v6/transport.go rename vendor/github.com/minio/minio-go/{ => v6}/utils.go (61%) create mode 100644 vendor/github.com/minio/sha256-simd/.gitignore create mode 100644 vendor/github.com/minio/sha256-simd/.travis.yml create mode 100644 vendor/github.com/minio/sha256-simd/LICENSE create mode 100644 vendor/github.com/minio/sha256-simd/README.md rename vendor/github.com/minio/{minio-go => sha256-simd}/appveyor.yml (51%) create mode 100644 vendor/github.com/minio/sha256-simd/cpuid.go create mode 100644 vendor/github.com/minio/sha256-simd/cpuid_386.go create mode 100644 vendor/github.com/minio/sha256-simd/cpuid_386.s create mode 100644 vendor/github.com/minio/sha256-simd/cpuid_amd64.go create mode 100644 vendor/github.com/minio/sha256-simd/cpuid_amd64.s create mode 100644 vendor/github.com/minio/sha256-simd/cpuid_arm.go create mode 100644 vendor/github.com/minio/sha256-simd/cpuid_linux_arm64.go create mode 100644 vendor/github.com/minio/sha256-simd/cpuid_other.go create mode 100644 vendor/github.com/minio/sha256-simd/go.mod create mode 100644 vendor/github.com/minio/sha256-simd/sha256.go create mode 100644 vendor/github.com/minio/sha256-simd/sha256blockAvx2_amd64.go create mode 100644 vendor/github.com/minio/sha256-simd/sha256blockAvx2_amd64.s create mode 100644 vendor/github.com/minio/sha256-simd/sha256blockAvx512_amd64.asm create mode 100644 vendor/github.com/minio/sha256-simd/sha256blockAvx512_amd64.go create mode 100644 vendor/github.com/minio/sha256-simd/sha256blockAvx512_amd64.s create mode 100644 vendor/github.com/minio/sha256-simd/sha256blockAvx_amd64.go create mode 100644 vendor/github.com/minio/sha256-simd/sha256blockAvx_amd64.s create mode 100644 vendor/github.com/minio/sha256-simd/sha256blockSha_amd64.go create mode 100644 vendor/github.com/minio/sha256-simd/sha256blockSha_amd64.s create mode 100644 vendor/github.com/minio/sha256-simd/sha256blockSsse_amd64.go create mode 100644 vendor/github.com/minio/sha256-simd/sha256blockSsse_amd64.s create mode 100644 vendor/github.com/minio/sha256-simd/sha256block_amd64.go create mode 100644 vendor/github.com/minio/sha256-simd/sha256block_arm64.go create mode 100644 vendor/github.com/minio/sha256-simd/sha256block_arm64.s create mode 100644 vendor/github.com/minio/sha256-simd/sha256block_other.go create mode 100644 vendor/github.com/minio/sha256-simd/test-architectures.sh create mode 100644 vendor/github.com/modern-go/concurrent/.gitignore create mode 100644 vendor/github.com/modern-go/concurrent/.travis.yml create mode 100644 vendor/github.com/modern-go/concurrent/LICENSE create mode 100644 vendor/github.com/modern-go/concurrent/README.md create mode 100644 vendor/github.com/modern-go/concurrent/executor.go create mode 100644 vendor/github.com/modern-go/concurrent/go_above_19.go create mode 100644 vendor/github.com/modern-go/concurrent/go_below_19.go create mode 100644 vendor/github.com/modern-go/concurrent/log.go create mode 100644 vendor/github.com/modern-go/concurrent/test.sh create mode 100644 vendor/github.com/modern-go/concurrent/unbounded_executor.go create mode 100644 vendor/github.com/modern-go/reflect2/.gitignore create mode 100644 vendor/github.com/modern-go/reflect2/.travis.yml create mode 100644 vendor/github.com/modern-go/reflect2/Gopkg.lock create mode 100644 vendor/github.com/modern-go/reflect2/Gopkg.toml create mode 100644 vendor/github.com/modern-go/reflect2/LICENSE create mode 100644 vendor/github.com/modern-go/reflect2/README.md create mode 100644 vendor/github.com/modern-go/reflect2/go_above_17.go create mode 100644 vendor/github.com/modern-go/reflect2/go_above_19.go create mode 100644 vendor/github.com/modern-go/reflect2/go_below_17.go create mode 100644 vendor/github.com/modern-go/reflect2/go_below_19.go create mode 100644 vendor/github.com/modern-go/reflect2/reflect2.go create mode 100644 vendor/github.com/modern-go/reflect2/reflect2_amd64.s create mode 100644 vendor/github.com/modern-go/reflect2/reflect2_kind.go create mode 100644 vendor/github.com/modern-go/reflect2/relfect2_386.s create mode 100644 vendor/github.com/modern-go/reflect2/relfect2_amd64p32.s create mode 100644 vendor/github.com/modern-go/reflect2/relfect2_arm.s create mode 100644 vendor/github.com/modern-go/reflect2/relfect2_arm64.s create mode 100644 vendor/github.com/modern-go/reflect2/relfect2_mips64x.s create mode 100644 vendor/github.com/modern-go/reflect2/relfect2_mipsx.s create mode 100644 vendor/github.com/modern-go/reflect2/relfect2_ppc64x.s create mode 100644 vendor/github.com/modern-go/reflect2/relfect2_s390x.s create mode 100644 vendor/github.com/modern-go/reflect2/safe_field.go create mode 100644 vendor/github.com/modern-go/reflect2/safe_map.go create mode 100644 vendor/github.com/modern-go/reflect2/safe_slice.go create mode 100644 vendor/github.com/modern-go/reflect2/safe_struct.go create mode 100644 vendor/github.com/modern-go/reflect2/safe_type.go create mode 100644 vendor/github.com/modern-go/reflect2/test.sh create mode 100644 vendor/github.com/modern-go/reflect2/type_map.go create mode 100644 vendor/github.com/modern-go/reflect2/unsafe_array.go create mode 100644 vendor/github.com/modern-go/reflect2/unsafe_eface.go create mode 100644 vendor/github.com/modern-go/reflect2/unsafe_field.go create mode 100644 vendor/github.com/modern-go/reflect2/unsafe_iface.go create mode 100644 vendor/github.com/modern-go/reflect2/unsafe_link.go create mode 100644 vendor/github.com/modern-go/reflect2/unsafe_map.go create mode 100644 vendor/github.com/modern-go/reflect2/unsafe_ptr.go create mode 100644 vendor/github.com/modern-go/reflect2/unsafe_slice.go create mode 100644 vendor/github.com/modern-go/reflect2/unsafe_struct.go create mode 100644 vendor/github.com/modern-go/reflect2/unsafe_type.go diff --git a/go.mod b/go.mod index ed755f07d4e23..f6c7bb3e9ac57 100644 --- a/go.mod +++ b/go.mod @@ -41,7 +41,6 @@ require ( github.com/go-enry/go-enry/v2 v2.5.2 github.com/go-git/go-billy/v5 v5.0.0 github.com/go-git/go-git/v5 v5.1.0 - github.com/go-ini/ini v1.57.0 // indirect github.com/go-openapi/jsonreference v0.19.3 // indirect github.com/go-redis/redis v6.15.2+incompatible github.com/go-sql-driver/mysql v1.5.0 @@ -75,7 +74,7 @@ require ( github.com/mgechev/revive v1.0.2 github.com/mholt/archiver/v3 v3.3.0 github.com/microcosm-cc/bluemonday v1.0.3-0.20191119130333-0a75d7616912 - github.com/minio/minio-go v6.0.14+incompatible + github.com/minio/minio-go/v6 v6.0.57 github.com/mitchellh/go-homedir v1.1.0 github.com/msteinert/pam v0.0.0-20151204160544-02ccfbfaf0cc github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5 diff --git a/go.sum b/go.sum index a93bc0ba0326f..0da789ca71bf7 100644 --- a/go.sum +++ b/go.sum @@ -237,8 +237,6 @@ github.com/go-git/go-git-fixtures/v4 v4.0.1 h1:q+IFMfLx200Q3scvt2hN79JsEzy4AmBTp github.com/go-git/go-git-fixtures/v4 v4.0.1/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw= github.com/go-git/go-git/v5 v5.1.0 h1:HxJn9g/E7eYvKW3Fm7Jt4ee8LXfPOm/H1cdDu8vEssk= github.com/go-git/go-git/v5 v5.1.0/go.mod h1:ZKfuPUoY1ZqIG4QG9BDBh3G4gLM5zvPuSJAozQrZuyM= -github.com/go-ini/ini v1.57.0 h1:Qwzj3wZQW+Plax5Ntj+GYe07DfGj1OH+aL1nMTMaNow= -github.com/go-ini/ini v1.57.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= @@ -474,6 +472,8 @@ github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqx github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= @@ -492,6 +492,8 @@ github.com/klauspost/compress v1.9.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0 github.com/klauspost/compress v1.10.2 h1:Znfn6hXZAHaLPNnlqUYRrBSReFHYybslgv4PTiyz6P0= github.com/klauspost/compress v1.10.2/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/cpuid v1.2.3 h1:CCtW0xUnWGVINKvE/WWOYKdsPV6mawAtvQuSl8guwQs= +github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/pgzip v1.2.1 h1:oIPZROsWuPHpOdMVWLuJZXwgjhrW8r1yEX8UqMyeNHM= github.com/klauspost/pgzip v1.2.1/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/kljensen/snowball v0.6.0/go.mod h1:27N7E8fVU5H68RlUmnWwZCfxgt4POBJfENGMvNRhldw= @@ -567,15 +569,21 @@ github.com/mholt/archiver/v3 v3.3.0 h1:vWjhY8SQp5yzM9P6OJ/eZEkmi3UAbRrxCq48MxjAz github.com/mholt/archiver/v3 v3.3.0/go.mod h1:YnQtqsp+94Rwd0D/rk5cnLrxusUBUXg+08Ebtr1Mqao= github.com/microcosm-cc/bluemonday v1.0.3-0.20191119130333-0a75d7616912 h1:hJde9rA24hlTcAYSwJoXpDUyGtfKQ/jsofw+WaDqGrI= github.com/microcosm-cc/bluemonday v1.0.3-0.20191119130333-0a75d7616912/go.mod h1:8iwZnFn2CDDNZ0r6UXhF4xawGvzaqzCRa1n3/lO3W2w= -github.com/minio/minio-go v6.0.14+incompatible h1:fnV+GD28LeqdN6vT2XdGKW8Qe/IfjJDswNVuni6km9o= -github.com/minio/minio-go v6.0.14+incompatible/go.mod h1:7guKYtitv8dktvNUGrhzmNlA5wrAABTQXCoesZdFQO8= +github.com/minio/md5-simd v1.1.0 h1:QPfiOqlZH+Cj9teu0t9b1nTBfPbyTl16Of5MeuShdK4= +github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw= +github.com/minio/minio-go/v6 v6.0.57 h1:ixPkbKkyD7IhnluRgQpGSpHdpvNVaW6OD5R9IAO/9Tw= +github.com/minio/minio-go/v6 v6.0.57/go.mod h1:5+R/nM9Pwrh0vqF+HbYYDQ84wdUFPyXHkrdT4AIkifM= +github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU= +github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mrjones/oauth v0.0.0-20180629183705-f4e24b6d100c h1:3wkDRdxK92dF+c1ke2dtj7ZzemFWBHB9plnJOtlwdFA= github.com/mrjones/oauth v0.0.0-20180629183705-f4e24b6d100c/go.mod h1:skjdDftzkFALcuGzYSklqYd8gvat6F1gZJ4YPVbkZpM= @@ -681,6 +689,7 @@ github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v1.0.1 h1:voD4ITNjPL5jjBfgR/r8fPIIBrliWrWHeiJApdr3r4w= @@ -794,6 +803,7 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= diff --git a/modules/storage/minio.go b/modules/storage/minio.go index 65a34bcfac0f2..af3b107be2504 100644 --- a/modules/storage/minio.go +++ b/modules/storage/minio.go @@ -11,7 +11,7 @@ import ( "strings" "time" - "github.com/minio/minio-go" + "github.com/minio/minio-go/v6" ) var ( diff --git a/vendor/github.com/go-ini/ini/.gitignore b/vendor/github.com/go-ini/ini/.gitignore deleted file mode 100644 index 12411127b39ef..0000000000000 --- a/vendor/github.com/go-ini/ini/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -testdata/conf_out.ini -ini.sublime-project -ini.sublime-workspace -testdata/conf_reflect.ini -.idea -/.vscode diff --git a/vendor/github.com/go-ini/ini/LICENSE b/vendor/github.com/go-ini/ini/LICENSE deleted file mode 100644 index d361bbcdf5c98..0000000000000 --- a/vendor/github.com/go-ini/ini/LICENSE +++ /dev/null @@ -1,191 +0,0 @@ -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: - -You must give any other recipients of the Work or Derivative Works a copy of -this License; and -You must cause any modified files to carry prominent notices stating that You -changed the files; and -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 -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 2014 Unknwon - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT 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/github.com/go-ini/ini/Makefile b/vendor/github.com/go-ini/ini/Makefile deleted file mode 100644 index f3b0dae2d298d..0000000000000 --- a/vendor/github.com/go-ini/ini/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -.PHONY: build test bench vet coverage - -build: vet bench - -test: - go test -v -cover -race - -bench: - go test -v -cover -test.bench=. -test.benchmem - -vet: - go vet - -coverage: - go test -coverprofile=c.out && go tool cover -html=c.out && rm c.out diff --git a/vendor/github.com/go-ini/ini/README.md b/vendor/github.com/go-ini/ini/README.md deleted file mode 100644 index 5d65658b29415..0000000000000 --- a/vendor/github.com/go-ini/ini/README.md +++ /dev/null @@ -1,43 +0,0 @@ -# INI - -[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/go-ini/ini/Go?logo=github&style=for-the-badge)](https://github.com/go-ini/ini/actions?query=workflow%3AGo) -[![codecov](https://img.shields.io/codecov/c/github/go-ini/ini/master?logo=codecov&style=for-the-badge)](https://codecov.io/gh/go-ini/ini) -[![GoDoc](https://img.shields.io/badge/GoDoc-Reference-blue?style=for-the-badge&logo=go)](https://pkg.go.dev/github.com/go-ini/ini?tab=doc) -[![Sourcegraph](https://img.shields.io/badge/view%20on-Sourcegraph-brightgreen.svg?style=for-the-badge&logo=sourcegraph)](https://sourcegraph.com/github.com/go-ini/ini) - -![](https://avatars0.githubusercontent.com/u/10216035?v=3&s=200) - -Package ini provides INI file read and write functionality in Go. - -## Features - -- Load from multiple data sources(file, `[]byte`, `io.Reader` and `io.ReadCloser`) with overwrites. -- Read with recursion values. -- Read with parent-child sections. -- Read with auto-increment key names. -- Read with multiple-line values. -- Read with tons of helper methods. -- Read and convert values to Go types. -- Read and **WRITE** comments of sections and keys. -- Manipulate sections, keys and comments with ease. -- Keep sections and keys in order as you parse and save. - -## Installation - -The minimum requirement of Go is **1.6**. - -```sh -$ go get gopkg.in/ini.v1 -``` - -Please add `-u` flag to update in the future. - -## Getting Help - -- [Getting Started](https://ini.unknwon.io/docs/intro/getting_started) -- [API Documentation](https://gowalker.org/gopkg.in/ini.v1) -- 中国大陆镜像:https://ini.unknwon.cn - -## License - -This project is under Apache v2 License. See the [LICENSE](LICENSE) file for the full license text. diff --git a/vendor/github.com/go-ini/ini/codecov.yml b/vendor/github.com/go-ini/ini/codecov.yml deleted file mode 100644 index fc947f2308201..0000000000000 --- a/vendor/github.com/go-ini/ini/codecov.yml +++ /dev/null @@ -1,9 +0,0 @@ -coverage: - range: "60...95" - status: - project: - default: - threshold: 1% - -comment: - layout: 'diff, files' diff --git a/vendor/github.com/go-ini/ini/data_source.go b/vendor/github.com/go-ini/ini/data_source.go deleted file mode 100644 index c3a541f1d1b5c..0000000000000 --- a/vendor/github.com/go-ini/ini/data_source.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2019 Unknwon -// -// Licensed under the Apache License, Version 2.0 (the "License"): you may -// not use this file except in compliance with the License. You may obtain -// a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. - -package ini - -import ( - "bytes" - "fmt" - "io" - "io/ioutil" - "os" -) - -var ( - _ dataSource = (*sourceFile)(nil) - _ dataSource = (*sourceData)(nil) - _ dataSource = (*sourceReadCloser)(nil) -) - -// dataSource is an interface that returns object which can be read and closed. -type dataSource interface { - ReadCloser() (io.ReadCloser, error) -} - -// sourceFile represents an object that contains content on the local file system. -type sourceFile struct { - name string -} - -func (s sourceFile) ReadCloser() (_ io.ReadCloser, err error) { - return os.Open(s.name) -} - -// sourceData represents an object that contains content in memory. -type sourceData struct { - data []byte -} - -func (s *sourceData) ReadCloser() (io.ReadCloser, error) { - return ioutil.NopCloser(bytes.NewReader(s.data)), nil -} - -// sourceReadCloser represents an input stream with Close method. -type sourceReadCloser struct { - reader io.ReadCloser -} - -func (s *sourceReadCloser) ReadCloser() (io.ReadCloser, error) { - return s.reader, nil -} - -func parseDataSource(source interface{}) (dataSource, error) { - switch s := source.(type) { - case string: - return sourceFile{s}, nil - case []byte: - return &sourceData{s}, nil - case io.ReadCloser: - return &sourceReadCloser{s}, nil - case io.Reader: - return &sourceReadCloser{ioutil.NopCloser(s)}, nil - default: - return nil, fmt.Errorf("error parsing data source: unknown type %q", s) - } -} diff --git a/vendor/github.com/go-ini/ini/deprecated.go b/vendor/github.com/go-ini/ini/deprecated.go deleted file mode 100644 index e8bda06e6ffee..0000000000000 --- a/vendor/github.com/go-ini/ini/deprecated.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2019 Unknwon -// -// Licensed under the Apache License, Version 2.0 (the "License"): you may -// not use this file except in compliance with the License. You may obtain -// a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. - -package ini - -const ( - // Deprecated: Use "DefaultSection" instead. - DEFAULT_SECTION = DefaultSection -) - -var ( - // Deprecated: AllCapsUnderscore converts to format ALL_CAPS_UNDERSCORE. - AllCapsUnderscore = SnackCase -) diff --git a/vendor/github.com/go-ini/ini/error.go b/vendor/github.com/go-ini/ini/error.go deleted file mode 100644 index d88347c54bf62..0000000000000 --- a/vendor/github.com/go-ini/ini/error.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2016 Unknwon -// -// Licensed under the Apache License, Version 2.0 (the "License"): you may -// not use this file except in compliance with the License. You may obtain -// a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. - -package ini - -import ( - "fmt" -) - -// ErrDelimiterNotFound indicates the error type of no delimiter is found which there should be one. -type ErrDelimiterNotFound struct { - Line string -} - -// IsErrDelimiterNotFound returns true if the given error is an instance of ErrDelimiterNotFound. -func IsErrDelimiterNotFound(err error) bool { - _, ok := err.(ErrDelimiterNotFound) - return ok -} - -func (err ErrDelimiterNotFound) Error() string { - return fmt.Sprintf("key-value delimiter not found: %s", err.Line) -} diff --git a/vendor/github.com/go-ini/ini/file.go b/vendor/github.com/go-ini/ini/file.go deleted file mode 100644 index f95606f90fa3d..0000000000000 --- a/vendor/github.com/go-ini/ini/file.go +++ /dev/null @@ -1,509 +0,0 @@ -// Copyright 2017 Unknwon -// -// Licensed under the Apache License, Version 2.0 (the "License"): you may -// not use this file except in compliance with the License. You may obtain -// a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. - -package ini - -import ( - "bytes" - "errors" - "fmt" - "io" - "io/ioutil" - "os" - "strings" - "sync" -) - -// File represents a combination of one or more INI files in memory. -type File struct { - options LoadOptions - dataSources []dataSource - - // Should make things safe, but sometimes doesn't matter. - BlockMode bool - lock sync.RWMutex - - // To keep data in order. - sectionList []string - // To keep track of the index of a section with same name. - // This meta list is only used with non-unique section names are allowed. - sectionIndexes []int - - // Actual data is stored here. - sections map[string][]*Section - - NameMapper - ValueMapper -} - -// newFile initializes File object with given data sources. -func newFile(dataSources []dataSource, opts LoadOptions) *File { - if len(opts.KeyValueDelimiters) == 0 { - opts.KeyValueDelimiters = "=:" - } - if len(opts.KeyValueDelimiterOnWrite) == 0 { - opts.KeyValueDelimiterOnWrite = "=" - } - - return &File{ - BlockMode: true, - dataSources: dataSources, - sections: make(map[string][]*Section), - options: opts, - } -} - -// Empty returns an empty file object. -func Empty(opts ...LoadOptions) *File { - var opt LoadOptions - if len(opts) > 0 { - opt = opts[0] - } - - // Ignore error here, we are sure our data is good. - f, _ := LoadSources(opt, []byte("")) - return f -} - -// NewSection creates a new section. -func (f *File) NewSection(name string) (*Section, error) { - if len(name) == 0 { - return nil, errors.New("empty section name") - } - - if f.options.Insensitive && name != DefaultSection { - name = strings.ToLower(name) - } - - if f.BlockMode { - f.lock.Lock() - defer f.lock.Unlock() - } - - if !f.options.AllowNonUniqueSections && inSlice(name, f.sectionList) { - return f.sections[name][0], nil - } - - f.sectionList = append(f.sectionList, name) - - // NOTE: Append to indexes must happen before appending to sections, - // otherwise index will have off-by-one problem. - f.sectionIndexes = append(f.sectionIndexes, len(f.sections[name])) - - sec := newSection(f, name) - f.sections[name] = append(f.sections[name], sec) - - return sec, nil -} - -// NewRawSection creates a new section with an unparseable body. -func (f *File) NewRawSection(name, body string) (*Section, error) { - section, err := f.NewSection(name) - if err != nil { - return nil, err - } - - section.isRawSection = true - section.rawBody = body - return section, nil -} - -// NewSections creates a list of sections. -func (f *File) NewSections(names ...string) (err error) { - for _, name := range names { - if _, err = f.NewSection(name); err != nil { - return err - } - } - return nil -} - -// GetSection returns section by given name. -func (f *File) GetSection(name string) (*Section, error) { - secs, err := f.SectionsByName(name) - if err != nil { - return nil, err - } - - return secs[0], err -} - -// SectionsByName returns all sections with given name. -func (f *File) SectionsByName(name string) ([]*Section, error) { - if len(name) == 0 { - name = DefaultSection - } - if f.options.Insensitive { - name = strings.ToLower(name) - } - - if f.BlockMode { - f.lock.RLock() - defer f.lock.RUnlock() - } - - secs := f.sections[name] - if len(secs) == 0 { - return nil, fmt.Errorf("section %q does not exist", name) - } - - return secs, nil -} - -// Section assumes named section exists and returns a zero-value when not. -func (f *File) Section(name string) *Section { - sec, err := f.GetSection(name) - if err != nil { - // Note: It's OK here because the only possible error is empty section name, - // but if it's empty, this piece of code won't be executed. - sec, _ = f.NewSection(name) - return sec - } - return sec -} - -// SectionWithIndex assumes named section exists and returns a new section when not. -func (f *File) SectionWithIndex(name string, index int) *Section { - secs, err := f.SectionsByName(name) - if err != nil || len(secs) <= index { - // NOTE: It's OK here because the only possible error is empty section name, - // but if it's empty, this piece of code won't be executed. - newSec, _ := f.NewSection(name) - return newSec - } - - return secs[index] -} - -// Sections returns a list of Section stored in the current instance. -func (f *File) Sections() []*Section { - if f.BlockMode { - f.lock.RLock() - defer f.lock.RUnlock() - } - - sections := make([]*Section, len(f.sectionList)) - for i, name := range f.sectionList { - sections[i] = f.sections[name][f.sectionIndexes[i]] - } - return sections -} - -// ChildSections returns a list of child sections of given section name. -func (f *File) ChildSections(name string) []*Section { - return f.Section(name).ChildSections() -} - -// SectionStrings returns list of section names. -func (f *File) SectionStrings() []string { - list := make([]string, len(f.sectionList)) - copy(list, f.sectionList) - return list -} - -// DeleteSection deletes a section or all sections with given name. -func (f *File) DeleteSection(name string) { - secs, err := f.SectionsByName(name) - if err != nil { - return - } - - for i := 0; i < len(secs); i++ { - // For non-unique sections, it is always needed to remove the first one so - // in the next iteration, the subsequent section continue having index 0. - // Ignoring the error as index 0 never returns an error. - _ = f.DeleteSectionWithIndex(name, 0) - } -} - -// DeleteSectionWithIndex deletes a section with given name and index. -func (f *File) DeleteSectionWithIndex(name string, index int) error { - if !f.options.AllowNonUniqueSections && index != 0 { - return fmt.Errorf("delete section with non-zero index is only allowed when non-unique sections is enabled") - } - - if len(name) == 0 { - name = DefaultSection - } - if f.options.Insensitive { - name = strings.ToLower(name) - } - - if f.BlockMode { - f.lock.Lock() - defer f.lock.Unlock() - } - - // Count occurrences of the sections - occurrences := 0 - - sectionListCopy := make([]string, len(f.sectionList)) - copy(sectionListCopy, f.sectionList) - - for i, s := range sectionListCopy { - if s != name { - continue - } - - if occurrences == index { - if len(f.sections[name]) <= 1 { - delete(f.sections, name) // The last one in the map - } else { - f.sections[name] = append(f.sections[name][:index], f.sections[name][index+1:]...) - } - - // Fix section lists - f.sectionList = append(f.sectionList[:i], f.sectionList[i+1:]...) - f.sectionIndexes = append(f.sectionIndexes[:i], f.sectionIndexes[i+1:]...) - - } else if occurrences > index { - // Fix the indices of all following sections with this name. - f.sectionIndexes[i-1]-- - } - - occurrences++ - } - - return nil -} - -func (f *File) reload(s dataSource) error { - r, err := s.ReadCloser() - if err != nil { - return err - } - defer r.Close() - - return f.parse(r) -} - -// Reload reloads and parses all data sources. -func (f *File) Reload() (err error) { - for _, s := range f.dataSources { - if err = f.reload(s); err != nil { - // In loose mode, we create an empty default section for nonexistent files. - if os.IsNotExist(err) && f.options.Loose { - _ = f.parse(bytes.NewBuffer(nil)) - continue - } - return err - } - } - return nil -} - -// Append appends one or more data sources and reloads automatically. -func (f *File) Append(source interface{}, others ...interface{}) error { - ds, err := parseDataSource(source) - if err != nil { - return err - } - f.dataSources = append(f.dataSources, ds) - for _, s := range others { - ds, err = parseDataSource(s) - if err != nil { - return err - } - f.dataSources = append(f.dataSources, ds) - } - return f.Reload() -} - -func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) { - equalSign := DefaultFormatLeft + f.options.KeyValueDelimiterOnWrite + DefaultFormatRight - - if PrettyFormat || PrettyEqual { - equalSign = fmt.Sprintf(" %s ", f.options.KeyValueDelimiterOnWrite) - } - - // Use buffer to make sure target is safe until finish encoding. - buf := bytes.NewBuffer(nil) - for i, sname := range f.sectionList { - sec := f.SectionWithIndex(sname, f.sectionIndexes[i]) - if len(sec.Comment) > 0 { - // Support multiline comments - lines := strings.Split(sec.Comment, LineBreak) - for i := range lines { - if lines[i][0] != '#' && lines[i][0] != ';' { - lines[i] = "; " + lines[i] - } else { - lines[i] = lines[i][:1] + " " + strings.TrimSpace(lines[i][1:]) - } - - if _, err := buf.WriteString(lines[i] + LineBreak); err != nil { - return nil, err - } - } - } - - if i > 0 || DefaultHeader { - if _, err := buf.WriteString("[" + sname + "]" + LineBreak); err != nil { - return nil, err - } - } else { - // Write nothing if default section is empty - if len(sec.keyList) == 0 { - continue - } - } - - if sec.isRawSection { - if _, err := buf.WriteString(sec.rawBody); err != nil { - return nil, err - } - - if PrettySection { - // Put a line between sections - if _, err := buf.WriteString(LineBreak); err != nil { - return nil, err - } - } - continue - } - - // Count and generate alignment length and buffer spaces using the - // longest key. Keys may be modified if they contain certain characters so - // we need to take that into account in our calculation. - alignLength := 0 - if PrettyFormat { - for _, kname := range sec.keyList { - keyLength := len(kname) - // First case will surround key by ` and second by """ - if strings.Contains(kname, "\"") || strings.ContainsAny(kname, f.options.KeyValueDelimiters) { - keyLength += 2 - } else if strings.Contains(kname, "`") { - keyLength += 6 - } - - if keyLength > alignLength { - alignLength = keyLength - } - } - } - alignSpaces := bytes.Repeat([]byte(" "), alignLength) - - KeyList: - for _, kname := range sec.keyList { - key := sec.Key(kname) - if len(key.Comment) > 0 { - if len(indent) > 0 && sname != DefaultSection { - buf.WriteString(indent) - } - - // Support multiline comments - lines := strings.Split(key.Comment, LineBreak) - for i := range lines { - if lines[i][0] != '#' && lines[i][0] != ';' { - lines[i] = "; " + strings.TrimSpace(lines[i]) - } else { - lines[i] = lines[i][:1] + " " + strings.TrimSpace(lines[i][1:]) - } - - if _, err := buf.WriteString(lines[i] + LineBreak); err != nil { - return nil, err - } - } - } - - if len(indent) > 0 && sname != DefaultSection { - buf.WriteString(indent) - } - - switch { - case key.isAutoIncrement: - kname = "-" - case strings.Contains(kname, "\"") || strings.ContainsAny(kname, f.options.KeyValueDelimiters): - kname = "`" + kname + "`" - case strings.Contains(kname, "`"): - kname = `"""` + kname + `"""` - } - - for _, val := range key.ValueWithShadows() { - if _, err := buf.WriteString(kname); err != nil { - return nil, err - } - - if key.isBooleanType { - if kname != sec.keyList[len(sec.keyList)-1] { - buf.WriteString(LineBreak) - } - continue KeyList - } - - // Write out alignment spaces before "=" sign - if PrettyFormat { - buf.Write(alignSpaces[:alignLength-len(kname)]) - } - - // In case key value contains "\n", "`", "\"", "#" or ";" - if strings.ContainsAny(val, "\n`") { - val = `"""` + val + `"""` - } else if !f.options.IgnoreInlineComment && strings.ContainsAny(val, "#;") { - val = "`" + val + "`" - } - if _, err := buf.WriteString(equalSign + val + LineBreak); err != nil { - return nil, err - } - } - - for _, val := range key.nestedValues { - if _, err := buf.WriteString(indent + " " + val + LineBreak); err != nil { - return nil, err - } - } - } - - if PrettySection { - // Put a line between sections - if _, err := buf.WriteString(LineBreak); err != nil { - return nil, err - } - } - } - - return buf, nil -} - -// WriteToIndent writes content into io.Writer with given indention. -// If PrettyFormat has been set to be true, -// it will align "=" sign with spaces under each section. -func (f *File) WriteToIndent(w io.Writer, indent string) (int64, error) { - buf, err := f.writeToBuffer(indent) - if err != nil { - return 0, err - } - return buf.WriteTo(w) -} - -// WriteTo writes file content into io.Writer. -func (f *File) WriteTo(w io.Writer) (int64, error) { - return f.WriteToIndent(w, "") -} - -// SaveToIndent writes content to file system with given value indention. -func (f *File) SaveToIndent(filename, indent string) error { - // Note: Because we are truncating with os.Create, - // so it's safer to save to a temporary file location and rename afte done. - buf, err := f.writeToBuffer(indent) - if err != nil { - return err - } - - return ioutil.WriteFile(filename, buf.Bytes(), 0666) -} - -// SaveTo writes content to file system. -func (f *File) SaveTo(filename string) error { - return f.SaveToIndent(filename, "") -} diff --git a/vendor/github.com/go-ini/ini/helper.go b/vendor/github.com/go-ini/ini/helper.go deleted file mode 100644 index f9d80a682a554..0000000000000 --- a/vendor/github.com/go-ini/ini/helper.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2019 Unknwon -// -// Licensed under the Apache License, Version 2.0 (the "License"): you may -// not use this file except in compliance with the License. You may obtain -// a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. - -package ini - -func inSlice(str string, s []string) bool { - for _, v := range s { - if str == v { - return true - } - } - return false -} diff --git a/vendor/github.com/go-ini/ini/ini.go b/vendor/github.com/go-ini/ini/ini.go deleted file mode 100644 index 2961543f918b9..0000000000000 --- a/vendor/github.com/go-ini/ini/ini.go +++ /dev/null @@ -1,168 +0,0 @@ -// +build go1.6 - -// Copyright 2014 Unknwon -// -// Licensed under the Apache License, Version 2.0 (the "License"): you may -// not use this file except in compliance with the License. You may obtain -// a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. - -// Package ini provides INI file read and write functionality in Go. -package ini - -import ( - "os" - "regexp" - "runtime" - "strings" -) - -const ( - // DefaultSection is the name of default section. You can use this constant or the string literal. - // In most of cases, an empty string is all you need to access the section. - DefaultSection = "DEFAULT" - - // Maximum allowed depth when recursively substituing variable names. - depthValues = 99 -) - -var ( - // LineBreak is the delimiter to determine or compose a new line. - // This variable will be changed to "\r\n" automatically on Windows at package init time. - LineBreak = "\n" - - // Variable regexp pattern: %(variable)s - varPattern = regexp.MustCompile(`%\(([^)]+)\)s`) - - // DefaultHeader explicitly writes default section header. - DefaultHeader = false - - // PrettySection indicates whether to put a line between sections. - PrettySection = true - // PrettyFormat indicates whether to align "=" sign with spaces to produce pretty output - // or reduce all possible spaces for compact format. - PrettyFormat = true - // PrettyEqual places spaces around "=" sign even when PrettyFormat is false. - PrettyEqual = false - // DefaultFormatLeft places custom spaces on the left when PrettyFormat and PrettyEqual are both disabled. - DefaultFormatLeft = "" - // DefaultFormatRight places custom spaces on the right when PrettyFormat and PrettyEqual are both disabled. - DefaultFormatRight = "" -) - -var inTest = len(os.Args) > 0 && strings.HasSuffix(strings.TrimSuffix(os.Args[0], ".exe"), ".test") - -func init() { - if runtime.GOOS == "windows" && !inTest { - LineBreak = "\r\n" - } -} - -// LoadOptions contains all customized options used for load data source(s). -type LoadOptions struct { - // Loose indicates whether the parser should ignore nonexistent files or return error. - Loose bool - // Insensitive indicates whether the parser forces all section and key names to lowercase. - Insensitive bool - // IgnoreContinuation indicates whether to ignore continuation lines while parsing. - IgnoreContinuation bool - // IgnoreInlineComment indicates whether to ignore comments at the end of value and treat it as part of value. - IgnoreInlineComment bool - // SkipUnrecognizableLines indicates whether to skip unrecognizable lines that do not conform to key/value pairs. - SkipUnrecognizableLines bool - // AllowBooleanKeys indicates whether to allow boolean type keys or treat as value is missing. - // This type of keys are mostly used in my.cnf. - AllowBooleanKeys bool - // AllowShadows indicates whether to keep track of keys with same name under same section. - AllowShadows bool - // AllowNestedValues indicates whether to allow AWS-like nested values. - // Docs: http://docs.aws.amazon.com/cli/latest/topic/config-vars.html#nested-values - AllowNestedValues bool - // AllowPythonMultilineValues indicates whether to allow Python-like multi-line values. - // Docs: https://docs.python.org/3/library/configparser.html#supported-ini-file-structure - // Relevant quote: Values can also span multiple lines, as long as they are indented deeper - // than the first line of the value. - AllowPythonMultilineValues bool - // SpaceBeforeInlineComment indicates whether to allow comment symbols (\# and \;) inside value. - // Docs: https://docs.python.org/2/library/configparser.html - // Quote: Comments may appear on their own in an otherwise empty line, or may be entered in lines holding values or section names. - // In the latter case, they need to be preceded by a whitespace character to be recognized as a comment. - SpaceBeforeInlineComment bool - // UnescapeValueDoubleQuotes indicates whether to unescape double quotes inside value to regular format - // when value is surrounded by double quotes, e.g. key="a \"value\"" => key=a "value" - UnescapeValueDoubleQuotes bool - // UnescapeValueCommentSymbols indicates to unescape comment symbols (\# and \;) inside value to regular format - // when value is NOT surrounded by any quotes. - // Note: UNSTABLE, behavior might change to only unescape inside double quotes but may noy necessary at all. - UnescapeValueCommentSymbols bool - // UnparseableSections stores a list of blocks that are allowed with raw content which do not otherwise - // conform to key/value pairs. Specify the names of those blocks here. - UnparseableSections []string - // KeyValueDelimiters is the sequence of delimiters that are used to separate key and value. By default, it is "=:". - KeyValueDelimiters string - // KeyValueDelimiters is the delimiter that are used to separate key and value output. By default, it is "=". - KeyValueDelimiterOnWrite string - // PreserveSurroundedQuote indicates whether to preserve surrounded quote (single and double quotes). - PreserveSurroundedQuote bool - // DebugFunc is called to collect debug information (currently only useful to debug parsing Python-style multiline values). - DebugFunc DebugFunc - // ReaderBufferSize is the buffer size of the reader in bytes. - ReaderBufferSize int - // AllowNonUniqueSections indicates whether to allow sections with the same name multiple times. - AllowNonUniqueSections bool -} - -// DebugFunc is the type of function called to log parse events. -type DebugFunc func(message string) - -// LoadSources allows caller to apply customized options for loading from data source(s). -func LoadSources(opts LoadOptions, source interface{}, others ...interface{}) (_ *File, err error) { - sources := make([]dataSource, len(others)+1) - sources[0], err = parseDataSource(source) - if err != nil { - return nil, err - } - for i := range others { - sources[i+1], err = parseDataSource(others[i]) - if err != nil { - return nil, err - } - } - f := newFile(sources, opts) - if err = f.Reload(); err != nil { - return nil, err - } - return f, nil -} - -// Load loads and parses from INI data sources. -// Arguments can be mixed of file name with string type, or raw data in []byte. -// It will return error if list contains nonexistent files. -func Load(source interface{}, others ...interface{}) (*File, error) { - return LoadSources(LoadOptions{}, source, others...) -} - -// LooseLoad has exactly same functionality as Load function -// except it ignores nonexistent files instead of returning error. -func LooseLoad(source interface{}, others ...interface{}) (*File, error) { - return LoadSources(LoadOptions{Loose: true}, source, others...) -} - -// InsensitiveLoad has exactly same functionality as Load function -// except it forces all section and key names to be lowercased. -func InsensitiveLoad(source interface{}, others ...interface{}) (*File, error) { - return LoadSources(LoadOptions{Insensitive: true}, source, others...) -} - -// ShadowLoad has exactly same functionality as Load function -// except it allows have shadow keys. -func ShadowLoad(source interface{}, others ...interface{}) (*File, error) { - return LoadSources(LoadOptions{AllowShadows: true}, source, others...) -} diff --git a/vendor/github.com/go-ini/ini/key.go b/vendor/github.com/go-ini/ini/key.go deleted file mode 100644 index 8baafd9ea6d03..0000000000000 --- a/vendor/github.com/go-ini/ini/key.go +++ /dev/null @@ -1,829 +0,0 @@ -// Copyright 2014 Unknwon -// -// Licensed under the Apache License, Version 2.0 (the "License"): you may -// not use this file except in compliance with the License. You may obtain -// a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. - -package ini - -import ( - "bytes" - "errors" - "fmt" - "strconv" - "strings" - "time" -) - -// Key represents a key under a section. -type Key struct { - s *Section - Comment string - name string - value string - isAutoIncrement bool - isBooleanType bool - - isShadow bool - shadows []*Key - - nestedValues []string -} - -// newKey simply return a key object with given values. -func newKey(s *Section, name, val string) *Key { - return &Key{ - s: s, - name: name, - value: val, - } -} - -func (k *Key) addShadow(val string) error { - if k.isShadow { - return errors.New("cannot add shadow to another shadow key") - } else if k.isAutoIncrement || k.isBooleanType { - return errors.New("cannot add shadow to auto-increment or boolean key") - } - - // Deduplicate shadows based on their values. - if k.value == val { - return nil - } - for i := range k.shadows { - if k.shadows[i].value == val { - return nil - } - } - - shadow := newKey(k.s, k.name, val) - shadow.isShadow = true - k.shadows = append(k.shadows, shadow) - return nil -} - -// AddShadow adds a new shadow key to itself. -func (k *Key) AddShadow(val string) error { - if !k.s.f.options.AllowShadows { - return errors.New("shadow key is not allowed") - } - return k.addShadow(val) -} - -func (k *Key) addNestedValue(val string) error { - if k.isAutoIncrement || k.isBooleanType { - return errors.New("cannot add nested value to auto-increment or boolean key") - } - - k.nestedValues = append(k.nestedValues, val) - return nil -} - -// AddNestedValue adds a nested value to the key. -func (k *Key) AddNestedValue(val string) error { - if !k.s.f.options.AllowNestedValues { - return errors.New("nested value is not allowed") - } - return k.addNestedValue(val) -} - -// ValueMapper represents a mapping function for values, e.g. os.ExpandEnv -type ValueMapper func(string) string - -// Name returns name of key. -func (k *Key) Name() string { - return k.name -} - -// Value returns raw value of key for performance purpose. -func (k *Key) Value() string { - return k.value -} - -// ValueWithShadows returns raw values of key and its shadows if any. -func (k *Key) ValueWithShadows() []string { - if len(k.shadows) == 0 { - return []string{k.value} - } - vals := make([]string, len(k.shadows)+1) - vals[0] = k.value - for i := range k.shadows { - vals[i+1] = k.shadows[i].value - } - return vals -} - -// NestedValues returns nested values stored in the key. -// It is possible returned value is nil if no nested values stored in the key. -func (k *Key) NestedValues() []string { - return k.nestedValues -} - -// transformValue takes a raw value and transforms to its final string. -func (k *Key) transformValue(val string) string { - if k.s.f.ValueMapper != nil { - val = k.s.f.ValueMapper(val) - } - - // Fail-fast if no indicate char found for recursive value - if !strings.Contains(val, "%") { - return val - } - for i := 0; i < depthValues; i++ { - vr := varPattern.FindString(val) - if len(vr) == 0 { - break - } - - // Take off leading '%(' and trailing ')s'. - noption := vr[2 : len(vr)-2] - - // Search in the same section. - // If not found or found the key itself, then search again in default section. - nk, err := k.s.GetKey(noption) - if err != nil || k == nk { - nk, _ = k.s.f.Section("").GetKey(noption) - if nk == nil { - // Stop when no results found in the default section, - // and returns the value as-is. - break - } - } - - // Substitute by new value and take off leading '%(' and trailing ')s'. - val = strings.Replace(val, vr, nk.value, -1) - } - return val -} - -// String returns string representation of value. -func (k *Key) String() string { - return k.transformValue(k.value) -} - -// Validate accepts a validate function which can -// return modifed result as key value. -func (k *Key) Validate(fn func(string) string) string { - return fn(k.String()) -} - -// parseBool returns the boolean value represented by the string. -// -// It accepts 1, t, T, TRUE, true, True, YES, yes, Yes, y, ON, on, On, -// 0, f, F, FALSE, false, False, NO, no, No, n, OFF, off, Off. -// Any other value returns an error. -func parseBool(str string) (value bool, err error) { - switch str { - case "1", "t", "T", "true", "TRUE", "True", "YES", "yes", "Yes", "y", "ON", "on", "On": - return true, nil - case "0", "f", "F", "false", "FALSE", "False", "NO", "no", "No", "n", "OFF", "off", "Off": - return false, nil - } - return false, fmt.Errorf("parsing \"%s\": invalid syntax", str) -} - -// Bool returns bool type value. -func (k *Key) Bool() (bool, error) { - return parseBool(k.String()) -} - -// Float64 returns float64 type value. -func (k *Key) Float64() (float64, error) { - return strconv.ParseFloat(k.String(), 64) -} - -// Int returns int type value. -func (k *Key) Int() (int, error) { - v, err := strconv.ParseInt(k.String(), 0, 64) - return int(v), err -} - -// Int64 returns int64 type value. -func (k *Key) Int64() (int64, error) { - return strconv.ParseInt(k.String(), 0, 64) -} - -// Uint returns uint type valued. -func (k *Key) Uint() (uint, error) { - u, e := strconv.ParseUint(k.String(), 0, 64) - return uint(u), e -} - -// Uint64 returns uint64 type value. -func (k *Key) Uint64() (uint64, error) { - return strconv.ParseUint(k.String(), 0, 64) -} - -// Duration returns time.Duration type value. -func (k *Key) Duration() (time.Duration, error) { - return time.ParseDuration(k.String()) -} - -// TimeFormat parses with given format and returns time.Time type value. -func (k *Key) TimeFormat(format string) (time.Time, error) { - return time.Parse(format, k.String()) -} - -// Time parses with RFC3339 format and returns time.Time type value. -func (k *Key) Time() (time.Time, error) { - return k.TimeFormat(time.RFC3339) -} - -// MustString returns default value if key value is empty. -func (k *Key) MustString(defaultVal string) string { - val := k.String() - if len(val) == 0 { - k.value = defaultVal - return defaultVal - } - return val -} - -// MustBool always returns value without error, -// it returns false if error occurs. -func (k *Key) MustBool(defaultVal ...bool) bool { - val, err := k.Bool() - if len(defaultVal) > 0 && err != nil { - k.value = strconv.FormatBool(defaultVal[0]) - return defaultVal[0] - } - return val -} - -// MustFloat64 always returns value without error, -// it returns 0.0 if error occurs. -func (k *Key) MustFloat64(defaultVal ...float64) float64 { - val, err := k.Float64() - if len(defaultVal) > 0 && err != nil { - k.value = strconv.FormatFloat(defaultVal[0], 'f', -1, 64) - return defaultVal[0] - } - return val -} - -// MustInt always returns value without error, -// it returns 0 if error occurs. -func (k *Key) MustInt(defaultVal ...int) int { - val, err := k.Int() - if len(defaultVal) > 0 && err != nil { - k.value = strconv.FormatInt(int64(defaultVal[0]), 10) - return defaultVal[0] - } - return val -} - -// MustInt64 always returns value without error, -// it returns 0 if error occurs. -func (k *Key) MustInt64(defaultVal ...int64) int64 { - val, err := k.Int64() - if len(defaultVal) > 0 && err != nil { - k.value = strconv.FormatInt(defaultVal[0], 10) - return defaultVal[0] - } - return val -} - -// MustUint always returns value without error, -// it returns 0 if error occurs. -func (k *Key) MustUint(defaultVal ...uint) uint { - val, err := k.Uint() - if len(defaultVal) > 0 && err != nil { - k.value = strconv.FormatUint(uint64(defaultVal[0]), 10) - return defaultVal[0] - } - return val -} - -// MustUint64 always returns value without error, -// it returns 0 if error occurs. -func (k *Key) MustUint64(defaultVal ...uint64) uint64 { - val, err := k.Uint64() - if len(defaultVal) > 0 && err != nil { - k.value = strconv.FormatUint(defaultVal[0], 10) - return defaultVal[0] - } - return val -} - -// MustDuration always returns value without error, -// it returns zero value if error occurs. -func (k *Key) MustDuration(defaultVal ...time.Duration) time.Duration { - val, err := k.Duration() - if len(defaultVal) > 0 && err != nil { - k.value = defaultVal[0].String() - return defaultVal[0] - } - return val -} - -// MustTimeFormat always parses with given format and returns value without error, -// it returns zero value if error occurs. -func (k *Key) MustTimeFormat(format string, defaultVal ...time.Time) time.Time { - val, err := k.TimeFormat(format) - if len(defaultVal) > 0 && err != nil { - k.value = defaultVal[0].Format(format) - return defaultVal[0] - } - return val -} - -// MustTime always parses with RFC3339 format and returns value without error, -// it returns zero value if error occurs. -func (k *Key) MustTime(defaultVal ...time.Time) time.Time { - return k.MustTimeFormat(time.RFC3339, defaultVal...) -} - -// In always returns value without error, -// it returns default value if error occurs or doesn't fit into candidates. -func (k *Key) In(defaultVal string, candidates []string) string { - val := k.String() - for _, cand := range candidates { - if val == cand { - return val - } - } - return defaultVal -} - -// InFloat64 always returns value without error, -// it returns default value if error occurs or doesn't fit into candidates. -func (k *Key) InFloat64(defaultVal float64, candidates []float64) float64 { - val := k.MustFloat64() - for _, cand := range candidates { - if val == cand { - return val - } - } - return defaultVal -} - -// InInt always returns value without error, -// it returns default value if error occurs or doesn't fit into candidates. -func (k *Key) InInt(defaultVal int, candidates []int) int { - val := k.MustInt() - for _, cand := range candidates { - if val == cand { - return val - } - } - return defaultVal -} - -// InInt64 always returns value without error, -// it returns default value if error occurs or doesn't fit into candidates. -func (k *Key) InInt64(defaultVal int64, candidates []int64) int64 { - val := k.MustInt64() - for _, cand := range candidates { - if val == cand { - return val - } - } - return defaultVal -} - -// InUint always returns value without error, -// it returns default value if error occurs or doesn't fit into candidates. -func (k *Key) InUint(defaultVal uint, candidates []uint) uint { - val := k.MustUint() - for _, cand := range candidates { - if val == cand { - return val - } - } - return defaultVal -} - -// InUint64 always returns value without error, -// it returns default value if error occurs or doesn't fit into candidates. -func (k *Key) InUint64(defaultVal uint64, candidates []uint64) uint64 { - val := k.MustUint64() - for _, cand := range candidates { - if val == cand { - return val - } - } - return defaultVal -} - -// InTimeFormat always parses with given format and returns value without error, -// it returns default value if error occurs or doesn't fit into candidates. -func (k *Key) InTimeFormat(format string, defaultVal time.Time, candidates []time.Time) time.Time { - val := k.MustTimeFormat(format) - for _, cand := range candidates { - if val == cand { - return val - } - } - return defaultVal -} - -// InTime always parses with RFC3339 format and returns value without error, -// it returns default value if error occurs or doesn't fit into candidates. -func (k *Key) InTime(defaultVal time.Time, candidates []time.Time) time.Time { - return k.InTimeFormat(time.RFC3339, defaultVal, candidates) -} - -// RangeFloat64 checks if value is in given range inclusively, -// and returns default value if it's not. -func (k *Key) RangeFloat64(defaultVal, min, max float64) float64 { - val := k.MustFloat64() - if val < min || val > max { - return defaultVal - } - return val -} - -// RangeInt checks if value is in given range inclusively, -// and returns default value if it's not. -func (k *Key) RangeInt(defaultVal, min, max int) int { - val := k.MustInt() - if val < min || val > max { - return defaultVal - } - return val -} - -// RangeInt64 checks if value is in given range inclusively, -// and returns default value if it's not. -func (k *Key) RangeInt64(defaultVal, min, max int64) int64 { - val := k.MustInt64() - if val < min || val > max { - return defaultVal - } - return val -} - -// RangeTimeFormat checks if value with given format is in given range inclusively, -// and returns default value if it's not. -func (k *Key) RangeTimeFormat(format string, defaultVal, min, max time.Time) time.Time { - val := k.MustTimeFormat(format) - if val.Unix() < min.Unix() || val.Unix() > max.Unix() { - return defaultVal - } - return val -} - -// RangeTime checks if value with RFC3339 format is in given range inclusively, -// and returns default value if it's not. -func (k *Key) RangeTime(defaultVal, min, max time.Time) time.Time { - return k.RangeTimeFormat(time.RFC3339, defaultVal, min, max) -} - -// Strings returns list of string divided by given delimiter. -func (k *Key) Strings(delim string) []string { - str := k.String() - if len(str) == 0 { - return []string{} - } - - runes := []rune(str) - vals := make([]string, 0, 2) - var buf bytes.Buffer - escape := false - idx := 0 - for { - if escape { - escape = false - if runes[idx] != '\\' && !strings.HasPrefix(string(runes[idx:]), delim) { - buf.WriteRune('\\') - } - buf.WriteRune(runes[idx]) - } else { - if runes[idx] == '\\' { - escape = true - } else if strings.HasPrefix(string(runes[idx:]), delim) { - idx += len(delim) - 1 - vals = append(vals, strings.TrimSpace(buf.String())) - buf.Reset() - } else { - buf.WriteRune(runes[idx]) - } - } - idx++ - if idx == len(runes) { - break - } - } - - if buf.Len() > 0 { - vals = append(vals, strings.TrimSpace(buf.String())) - } - - return vals -} - -// StringsWithShadows returns list of string divided by given delimiter. -// Shadows will also be appended if any. -func (k *Key) StringsWithShadows(delim string) []string { - vals := k.ValueWithShadows() - results := make([]string, 0, len(vals)*2) - for i := range vals { - if len(vals) == 0 { - continue - } - - results = append(results, strings.Split(vals[i], delim)...) - } - - for i := range results { - results[i] = k.transformValue(strings.TrimSpace(results[i])) - } - return results -} - -// Float64s returns list of float64 divided by given delimiter. Any invalid input will be treated as zero value. -func (k *Key) Float64s(delim string) []float64 { - vals, _ := k.parseFloat64s(k.Strings(delim), true, false) - return vals -} - -// Ints returns list of int divided by given delimiter. Any invalid input will be treated as zero value. -func (k *Key) Ints(delim string) []int { - vals, _ := k.parseInts(k.Strings(delim), true, false) - return vals -} - -// Int64s returns list of int64 divided by given delimiter. Any invalid input will be treated as zero value. -func (k *Key) Int64s(delim string) []int64 { - vals, _ := k.parseInt64s(k.Strings(delim), true, false) - return vals -} - -// Uints returns list of uint divided by given delimiter. Any invalid input will be treated as zero value. -func (k *Key) Uints(delim string) []uint { - vals, _ := k.parseUints(k.Strings(delim), true, false) - return vals -} - -// Uint64s returns list of uint64 divided by given delimiter. Any invalid input will be treated as zero value. -func (k *Key) Uint64s(delim string) []uint64 { - vals, _ := k.parseUint64s(k.Strings(delim), true, false) - return vals -} - -// Bools returns list of bool divided by given delimiter. Any invalid input will be treated as zero value. -func (k *Key) Bools(delim string) []bool { - vals, _ := k.parseBools(k.Strings(delim), true, false) - return vals -} - -// TimesFormat parses with given format and returns list of time.Time divided by given delimiter. -// Any invalid input will be treated as zero value (0001-01-01 00:00:00 +0000 UTC). -func (k *Key) TimesFormat(format, delim string) []time.Time { - vals, _ := k.parseTimesFormat(format, k.Strings(delim), true, false) - return vals -} - -// Times parses with RFC3339 format and returns list of time.Time divided by given delimiter. -// Any invalid input will be treated as zero value (0001-01-01 00:00:00 +0000 UTC). -func (k *Key) Times(delim string) []time.Time { - return k.TimesFormat(time.RFC3339, delim) -} - -// ValidFloat64s returns list of float64 divided by given delimiter. If some value is not float, then -// it will not be included to result list. -func (k *Key) ValidFloat64s(delim string) []float64 { - vals, _ := k.parseFloat64s(k.Strings(delim), false, false) - return vals -} - -// ValidInts returns list of int divided by given delimiter. If some value is not integer, then it will -// not be included to result list. -func (k *Key) ValidInts(delim string) []int { - vals, _ := k.parseInts(k.Strings(delim), false, false) - return vals -} - -// ValidInt64s returns list of int64 divided by given delimiter. If some value is not 64-bit integer, -// then it will not be included to result list. -func (k *Key) ValidInt64s(delim string) []int64 { - vals, _ := k.parseInt64s(k.Strings(delim), false, false) - return vals -} - -// ValidUints returns list of uint divided by given delimiter. If some value is not unsigned integer, -// then it will not be included to result list. -func (k *Key) ValidUints(delim string) []uint { - vals, _ := k.parseUints(k.Strings(delim), false, false) - return vals -} - -// ValidUint64s returns list of uint64 divided by given delimiter. If some value is not 64-bit unsigned -// integer, then it will not be included to result list. -func (k *Key) ValidUint64s(delim string) []uint64 { - vals, _ := k.parseUint64s(k.Strings(delim), false, false) - return vals -} - -// ValidBools returns list of bool divided by given delimiter. If some value is not 64-bit unsigned -// integer, then it will not be included to result list. -func (k *Key) ValidBools(delim string) []bool { - vals, _ := k.parseBools(k.Strings(delim), false, false) - return vals -} - -// ValidTimesFormat parses with given format and returns list of time.Time divided by given delimiter. -func (k *Key) ValidTimesFormat(format, delim string) []time.Time { - vals, _ := k.parseTimesFormat(format, k.Strings(delim), false, false) - return vals -} - -// ValidTimes parses with RFC3339 format and returns list of time.Time divided by given delimiter. -func (k *Key) ValidTimes(delim string) []time.Time { - return k.ValidTimesFormat(time.RFC3339, delim) -} - -// StrictFloat64s returns list of float64 divided by given delimiter or error on first invalid input. -func (k *Key) StrictFloat64s(delim string) ([]float64, error) { - return k.parseFloat64s(k.Strings(delim), false, true) -} - -// StrictInts returns list of int divided by given delimiter or error on first invalid input. -func (k *Key) StrictInts(delim string) ([]int, error) { - return k.parseInts(k.Strings(delim), false, true) -} - -// StrictInt64s returns list of int64 divided by given delimiter or error on first invalid input. -func (k *Key) StrictInt64s(delim string) ([]int64, error) { - return k.parseInt64s(k.Strings(delim), false, true) -} - -// StrictUints returns list of uint divided by given delimiter or error on first invalid input. -func (k *Key) StrictUints(delim string) ([]uint, error) { - return k.parseUints(k.Strings(delim), false, true) -} - -// StrictUint64s returns list of uint64 divided by given delimiter or error on first invalid input. -func (k *Key) StrictUint64s(delim string) ([]uint64, error) { - return k.parseUint64s(k.Strings(delim), false, true) -} - -// StrictBools returns list of bool divided by given delimiter or error on first invalid input. -func (k *Key) StrictBools(delim string) ([]bool, error) { - return k.parseBools(k.Strings(delim), false, true) -} - -// StrictTimesFormat parses with given format and returns list of time.Time divided by given delimiter -// or error on first invalid input. -func (k *Key) StrictTimesFormat(format, delim string) ([]time.Time, error) { - return k.parseTimesFormat(format, k.Strings(delim), false, true) -} - -// StrictTimes parses with RFC3339 format and returns list of time.Time divided by given delimiter -// or error on first invalid input. -func (k *Key) StrictTimes(delim string) ([]time.Time, error) { - return k.StrictTimesFormat(time.RFC3339, delim) -} - -// parseBools transforms strings to bools. -func (k *Key) parseBools(strs []string, addInvalid, returnOnInvalid bool) ([]bool, error) { - vals := make([]bool, 0, len(strs)) - parser := func(str string) (interface{}, error) { - val, err := parseBool(str) - return val, err - } - rawVals, err := k.doParse(strs, addInvalid, returnOnInvalid, parser) - if err == nil { - for _, val := range rawVals { - vals = append(vals, val.(bool)) - } - } - return vals, err -} - -// parseFloat64s transforms strings to float64s. -func (k *Key) parseFloat64s(strs []string, addInvalid, returnOnInvalid bool) ([]float64, error) { - vals := make([]float64, 0, len(strs)) - parser := func(str string) (interface{}, error) { - val, err := strconv.ParseFloat(str, 64) - return val, err - } - rawVals, err := k.doParse(strs, addInvalid, returnOnInvalid, parser) - if err == nil { - for _, val := range rawVals { - vals = append(vals, val.(float64)) - } - } - return vals, err -} - -// parseInts transforms strings to ints. -func (k *Key) parseInts(strs []string, addInvalid, returnOnInvalid bool) ([]int, error) { - vals := make([]int, 0, len(strs)) - parser := func(str string) (interface{}, error) { - val, err := strconv.ParseInt(str, 0, 64) - return val, err - } - rawVals, err := k.doParse(strs, addInvalid, returnOnInvalid, parser) - if err == nil { - for _, val := range rawVals { - vals = append(vals, int(val.(int64))) - } - } - return vals, err -} - -// parseInt64s transforms strings to int64s. -func (k *Key) parseInt64s(strs []string, addInvalid, returnOnInvalid bool) ([]int64, error) { - vals := make([]int64, 0, len(strs)) - parser := func(str string) (interface{}, error) { - val, err := strconv.ParseInt(str, 0, 64) - return val, err - } - - rawVals, err := k.doParse(strs, addInvalid, returnOnInvalid, parser) - if err == nil { - for _, val := range rawVals { - vals = append(vals, val.(int64)) - } - } - return vals, err -} - -// parseUints transforms strings to uints. -func (k *Key) parseUints(strs []string, addInvalid, returnOnInvalid bool) ([]uint, error) { - vals := make([]uint, 0, len(strs)) - parser := func(str string) (interface{}, error) { - val, err := strconv.ParseUint(str, 0, 64) - return val, err - } - - rawVals, err := k.doParse(strs, addInvalid, returnOnInvalid, parser) - if err == nil { - for _, val := range rawVals { - vals = append(vals, uint(val.(uint64))) - } - } - return vals, err -} - -// parseUint64s transforms strings to uint64s. -func (k *Key) parseUint64s(strs []string, addInvalid, returnOnInvalid bool) ([]uint64, error) { - vals := make([]uint64, 0, len(strs)) - parser := func(str string) (interface{}, error) { - val, err := strconv.ParseUint(str, 0, 64) - return val, err - } - rawVals, err := k.doParse(strs, addInvalid, returnOnInvalid, parser) - if err == nil { - for _, val := range rawVals { - vals = append(vals, val.(uint64)) - } - } - return vals, err -} - - -type Parser func(str string) (interface{}, error) - - -// parseTimesFormat transforms strings to times in given format. -func (k *Key) parseTimesFormat(format string, strs []string, addInvalid, returnOnInvalid bool) ([]time.Time, error) { - vals := make([]time.Time, 0, len(strs)) - parser := func(str string) (interface{}, error) { - val, err := time.Parse(format, str) - return val, err - } - rawVals, err := k.doParse(strs, addInvalid, returnOnInvalid, parser) - if err == nil { - for _, val := range rawVals { - vals = append(vals, val.(time.Time)) - } - } - return vals, err -} - - -// doParse transforms strings to different types -func (k *Key) doParse(strs []string, addInvalid, returnOnInvalid bool, parser Parser) ([]interface{}, error) { - vals := make([]interface{}, 0, len(strs)) - for _, str := range strs { - val, err := parser(str) - if err != nil && returnOnInvalid { - return nil, err - } - if err == nil || addInvalid { - vals = append(vals, val) - } - } - return vals, nil -} - -// SetValue changes key value. -func (k *Key) SetValue(v string) { - if k.s.f.BlockMode { - k.s.f.lock.Lock() - defer k.s.f.lock.Unlock() - } - - k.value = v - k.s.keysHash[k.name] = v -} diff --git a/vendor/github.com/go-ini/ini/parser.go b/vendor/github.com/go-ini/ini/parser.go deleted file mode 100644 index ea6c08b02918c..0000000000000 --- a/vendor/github.com/go-ini/ini/parser.go +++ /dev/null @@ -1,535 +0,0 @@ -// Copyright 2015 Unknwon -// -// Licensed under the Apache License, Version 2.0 (the "License"): you may -// not use this file except in compliance with the License. You may obtain -// a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. - -package ini - -import ( - "bufio" - "bytes" - "fmt" - "io" - "regexp" - "strconv" - "strings" - "unicode" -) - -const minReaderBufferSize = 4096 - -var pythonMultiline = regexp.MustCompile(`^([\t\f ]+)(.*)`) - -type parserOptions struct { - IgnoreContinuation bool - IgnoreInlineComment bool - AllowPythonMultilineValues bool - SpaceBeforeInlineComment bool - UnescapeValueDoubleQuotes bool - UnescapeValueCommentSymbols bool - PreserveSurroundedQuote bool - DebugFunc DebugFunc - ReaderBufferSize int -} - -type parser struct { - buf *bufio.Reader - options parserOptions - - isEOF bool - count int - comment *bytes.Buffer -} - -func (p *parser) debug(format string, args ...interface{}) { - if p.options.DebugFunc != nil { - p.options.DebugFunc(fmt.Sprintf(format, args...)) - } -} - -func newParser(r io.Reader, opts parserOptions) *parser { - size := opts.ReaderBufferSize - if size < minReaderBufferSize { - size = minReaderBufferSize - } - - return &parser{ - buf: bufio.NewReaderSize(r, size), - options: opts, - count: 1, - comment: &bytes.Buffer{}, - } -} - -// BOM handles header of UTF-8, UTF-16 LE and UTF-16 BE's BOM format. -// http://en.wikipedia.org/wiki/Byte_order_mark#Representations_of_byte_order_marks_by_encoding -func (p *parser) BOM() error { - mask, err := p.buf.Peek(2) - if err != nil && err != io.EOF { - return err - } else if len(mask) < 2 { - return nil - } - - switch { - case mask[0] == 254 && mask[1] == 255: - fallthrough - case mask[0] == 255 && mask[1] == 254: - _, err = p.buf.Read(mask) - if err != nil { - return err - } - case mask[0] == 239 && mask[1] == 187: - mask, err := p.buf.Peek(3) - if err != nil && err != io.EOF { - return err - } else if len(mask) < 3 { - return nil - } - if mask[2] == 191 { - _, err = p.buf.Read(mask) - if err != nil { - return err - } - } - } - return nil -} - -func (p *parser) readUntil(delim byte) ([]byte, error) { - data, err := p.buf.ReadBytes(delim) - if err != nil { - if err == io.EOF { - p.isEOF = true - } else { - return nil, err - } - } - return data, nil -} - -func cleanComment(in []byte) ([]byte, bool) { - i := bytes.IndexAny(in, "#;") - if i == -1 { - return nil, false - } - return in[i:], true -} - -func readKeyName(delimiters string, in []byte) (string, int, error) { - line := string(in) - - // Check if key name surrounded by quotes. - var keyQuote string - if line[0] == '"' { - if len(line) > 6 && string(line[0:3]) == `"""` { - keyQuote = `"""` - } else { - keyQuote = `"` - } - } else if line[0] == '`' { - keyQuote = "`" - } - - // Get out key name - var endIdx int - if len(keyQuote) > 0 { - startIdx := len(keyQuote) - // FIXME: fail case -> """"""name"""=value - pos := strings.Index(line[startIdx:], keyQuote) - if pos == -1 { - return "", -1, fmt.Errorf("missing closing key quote: %s", line) - } - pos += startIdx - - // Find key-value delimiter - i := strings.IndexAny(line[pos+startIdx:], delimiters) - if i < 0 { - return "", -1, ErrDelimiterNotFound{line} - } - endIdx = pos + i - return strings.TrimSpace(line[startIdx:pos]), endIdx + startIdx + 1, nil - } - - endIdx = strings.IndexAny(line, delimiters) - if endIdx < 0 { - return "", -1, ErrDelimiterNotFound{line} - } - return strings.TrimSpace(line[0:endIdx]), endIdx + 1, nil -} - -func (p *parser) readMultilines(line, val, valQuote string) (string, error) { - for { - data, err := p.readUntil('\n') - if err != nil { - return "", err - } - next := string(data) - - pos := strings.LastIndex(next, valQuote) - if pos > -1 { - val += next[:pos] - - comment, has := cleanComment([]byte(next[pos:])) - if has { - p.comment.Write(bytes.TrimSpace(comment)) - } - break - } - val += next - if p.isEOF { - return "", fmt.Errorf("missing closing key quote from %q to %q", line, next) - } - } - return val, nil -} - -func (p *parser) readContinuationLines(val string) (string, error) { - for { - data, err := p.readUntil('\n') - if err != nil { - return "", err - } - next := strings.TrimSpace(string(data)) - - if len(next) == 0 { - break - } - val += next - if val[len(val)-1] != '\\' { - break - } - val = val[:len(val)-1] - } - return val, nil -} - -// hasSurroundedQuote check if and only if the first and last characters -// are quotes \" or \'. -// It returns false if any other parts also contain same kind of quotes. -func hasSurroundedQuote(in string, quote byte) bool { - return len(in) >= 2 && in[0] == quote && in[len(in)-1] == quote && - strings.IndexByte(in[1:], quote) == len(in)-2 -} - -func (p *parser) readValue(in []byte, bufferSize int) (string, error) { - - line := strings.TrimLeftFunc(string(in), unicode.IsSpace) - if len(line) == 0 { - if p.options.AllowPythonMultilineValues && len(in) > 0 && in[len(in)-1] == '\n' { - return p.readPythonMultilines(line, bufferSize) - } - return "", nil - } - - var valQuote string - if len(line) > 3 && string(line[0:3]) == `"""` { - valQuote = `"""` - } else if line[0] == '`' { - valQuote = "`" - } else if p.options.UnescapeValueDoubleQuotes && line[0] == '"' { - valQuote = `"` - } - - if len(valQuote) > 0 { - startIdx := len(valQuote) - pos := strings.LastIndex(line[startIdx:], valQuote) - // Check for multi-line value - if pos == -1 { - return p.readMultilines(line, line[startIdx:], valQuote) - } - - if p.options.UnescapeValueDoubleQuotes && valQuote == `"` { - return strings.Replace(line[startIdx:pos+startIdx], `\"`, `"`, -1), nil - } - return line[startIdx : pos+startIdx], nil - } - - lastChar := line[len(line)-1] - // Won't be able to reach here if value only contains whitespace - line = strings.TrimSpace(line) - trimmedLastChar := line[len(line)-1] - - // Check continuation lines when desired - if !p.options.IgnoreContinuation && trimmedLastChar == '\\' { - return p.readContinuationLines(line[:len(line)-1]) - } - - // Check if ignore inline comment - if !p.options.IgnoreInlineComment { - var i int - if p.options.SpaceBeforeInlineComment { - i = strings.Index(line, " #") - if i == -1 { - i = strings.Index(line, " ;") - } - - } else { - i = strings.IndexAny(line, "#;") - } - - if i > -1 { - p.comment.WriteString(line[i:]) - line = strings.TrimSpace(line[:i]) - } - - } - - // Trim single and double quotes - if (hasSurroundedQuote(line, '\'') || - hasSurroundedQuote(line, '"')) && !p.options.PreserveSurroundedQuote { - line = line[1 : len(line)-1] - } else if len(valQuote) == 0 && p.options.UnescapeValueCommentSymbols { - if strings.Contains(line, `\;`) { - line = strings.Replace(line, `\;`, ";", -1) - } - if strings.Contains(line, `\#`) { - line = strings.Replace(line, `\#`, "#", -1) - } - } else if p.options.AllowPythonMultilineValues && lastChar == '\n' { - return p.readPythonMultilines(line, bufferSize) - } - - return line, nil -} - -func (p *parser) readPythonMultilines(line string, bufferSize int) (string, error) { - parserBufferPeekResult, _ := p.buf.Peek(bufferSize) - peekBuffer := bytes.NewBuffer(parserBufferPeekResult) - - indentSize := 0 - for { - peekData, peekErr := peekBuffer.ReadBytes('\n') - if peekErr != nil { - if peekErr == io.EOF { - p.debug("readPythonMultilines: io.EOF, peekData: %q, line: %q", string(peekData), line) - return line, nil - } - - p.debug("readPythonMultilines: failed to peek with error: %v", peekErr) - return "", peekErr - } - - p.debug("readPythonMultilines: parsing %q", string(peekData)) - - peekMatches := pythonMultiline.FindStringSubmatch(string(peekData)) - p.debug("readPythonMultilines: matched %d parts", len(peekMatches)) - for n, v := range peekMatches { - p.debug(" %d: %q", n, v) - } - - // Return if not a Python multiline value. - if len(peekMatches) != 3 { - p.debug("readPythonMultilines: end of value, got: %q", line) - return line, nil - } - - // Determine indent size and line prefix. - currentIndentSize := len(peekMatches[1]) - if indentSize < 1 { - indentSize = currentIndentSize - p.debug("readPythonMultilines: indent size is %d", indentSize) - } - - // Make sure each line is indented at least as far as first line. - if currentIndentSize < indentSize { - p.debug("readPythonMultilines: end of value, current indent: %d, expected indent: %d, line: %q", currentIndentSize, indentSize, line) - return line, nil - } - - // Advance the parser reader (buffer) in-sync with the peek buffer. - _, err := p.buf.Discard(len(peekData)) - if err != nil { - p.debug("readPythonMultilines: failed to skip to the end, returning error") - return "", err - } - - // Handle indented empty line. - line += "\n" + peekMatches[1][indentSize:] + peekMatches[2] - } -} - -// parse parses data through an io.Reader. -func (f *File) parse(reader io.Reader) (err error) { - p := newParser(reader, parserOptions{ - IgnoreContinuation: f.options.IgnoreContinuation, - IgnoreInlineComment: f.options.IgnoreInlineComment, - AllowPythonMultilineValues: f.options.AllowPythonMultilineValues, - SpaceBeforeInlineComment: f.options.SpaceBeforeInlineComment, - UnescapeValueDoubleQuotes: f.options.UnescapeValueDoubleQuotes, - UnescapeValueCommentSymbols: f.options.UnescapeValueCommentSymbols, - PreserveSurroundedQuote: f.options.PreserveSurroundedQuote, - DebugFunc: f.options.DebugFunc, - ReaderBufferSize: f.options.ReaderBufferSize, - }) - if err = p.BOM(); err != nil { - return fmt.Errorf("BOM: %v", err) - } - - // Ignore error because default section name is never empty string. - name := DefaultSection - if f.options.Insensitive { - name = strings.ToLower(DefaultSection) - } - section, _ := f.NewSection(name) - - // This "last" is not strictly equivalent to "previous one" if current key is not the first nested key - var isLastValueEmpty bool - var lastRegularKey *Key - - var line []byte - var inUnparseableSection bool - - // NOTE: Iterate and increase `currentPeekSize` until - // the size of the parser buffer is found. - // TODO(unknwon): When Golang 1.10 is the lowest version supported, replace with `parserBufferSize := p.buf.Size()`. - parserBufferSize := 0 - // NOTE: Peek 4kb at a time. - currentPeekSize := minReaderBufferSize - - if f.options.AllowPythonMultilineValues { - for { - peekBytes, _ := p.buf.Peek(currentPeekSize) - peekBytesLength := len(peekBytes) - - if parserBufferSize >= peekBytesLength { - break - } - - currentPeekSize *= 2 - parserBufferSize = peekBytesLength - } - } - - for !p.isEOF { - line, err = p.readUntil('\n') - if err != nil { - return err - } - - if f.options.AllowNestedValues && - isLastValueEmpty && len(line) > 0 { - if line[0] == ' ' || line[0] == '\t' { - err = lastRegularKey.addNestedValue(string(bytes.TrimSpace(line))) - if err != nil { - return err - } - continue - } - } - - line = bytes.TrimLeftFunc(line, unicode.IsSpace) - if len(line) == 0 { - continue - } - - // Comments - if line[0] == '#' || line[0] == ';' { - // Note: we do not care ending line break, - // it is needed for adding second line, - // so just clean it once at the end when set to value. - p.comment.Write(line) - continue - } - - // Section - if line[0] == '[' { - // Read to the next ']' (TODO: support quoted strings) - closeIdx := bytes.LastIndexByte(line, ']') - if closeIdx == -1 { - return fmt.Errorf("unclosed section: %s", line) - } - - name := string(line[1:closeIdx]) - section, err = f.NewSection(name) - if err != nil { - return err - } - - comment, has := cleanComment(line[closeIdx+1:]) - if has { - p.comment.Write(comment) - } - - section.Comment = strings.TrimSpace(p.comment.String()) - - // Reset auto-counter and comments - p.comment.Reset() - p.count = 1 - - inUnparseableSection = false - for i := range f.options.UnparseableSections { - if f.options.UnparseableSections[i] == name || - (f.options.Insensitive && strings.EqualFold(f.options.UnparseableSections[i], name)) { - inUnparseableSection = true - continue - } - } - continue - } - - if inUnparseableSection { - section.isRawSection = true - section.rawBody += string(line) - continue - } - - kname, offset, err := readKeyName(f.options.KeyValueDelimiters, line) - if err != nil { - // Treat as boolean key when desired, and whole line is key name. - if IsErrDelimiterNotFound(err) { - switch { - case f.options.AllowBooleanKeys: - kname, err := p.readValue(line, parserBufferSize) - if err != nil { - return err - } - key, err := section.NewBooleanKey(kname) - if err != nil { - return err - } - key.Comment = strings.TrimSpace(p.comment.String()) - p.comment.Reset() - continue - - case f.options.SkipUnrecognizableLines: - continue - } - } - return err - } - - // Auto increment. - isAutoIncr := false - if kname == "-" { - isAutoIncr = true - kname = "#" + strconv.Itoa(p.count) - p.count++ - } - - value, err := p.readValue(line[offset:], parserBufferSize) - if err != nil { - return err - } - isLastValueEmpty = len(value) == 0 - - key, err := section.NewKey(kname, value) - if err != nil { - return err - } - key.isAutoIncrement = isAutoIncr - key.Comment = strings.TrimSpace(p.comment.String()) - p.comment.Reset() - lastRegularKey = key - } - return nil -} diff --git a/vendor/github.com/go-ini/ini/section.go b/vendor/github.com/go-ini/ini/section.go deleted file mode 100644 index 6ba5ac2905c83..0000000000000 --- a/vendor/github.com/go-ini/ini/section.go +++ /dev/null @@ -1,256 +0,0 @@ -// Copyright 2014 Unknwon -// -// Licensed under the Apache License, Version 2.0 (the "License"): you may -// not use this file except in compliance with the License. You may obtain -// a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. - -package ini - -import ( - "errors" - "fmt" - "strings" -) - -// Section represents a config section. -type Section struct { - f *File - Comment string - name string - keys map[string]*Key - keyList []string - keysHash map[string]string - - isRawSection bool - rawBody string -} - -func newSection(f *File, name string) *Section { - return &Section{ - f: f, - name: name, - keys: make(map[string]*Key), - keyList: make([]string, 0, 10), - keysHash: make(map[string]string), - } -} - -// Name returns name of Section. -func (s *Section) Name() string { - return s.name -} - -// Body returns rawBody of Section if the section was marked as unparseable. -// It still follows the other rules of the INI format surrounding leading/trailing whitespace. -func (s *Section) Body() string { - return strings.TrimSpace(s.rawBody) -} - -// SetBody updates body content only if section is raw. -func (s *Section) SetBody(body string) { - if !s.isRawSection { - return - } - s.rawBody = body -} - -// NewKey creates a new key to given section. -func (s *Section) NewKey(name, val string) (*Key, error) { - if len(name) == 0 { - return nil, errors.New("error creating new key: empty key name") - } else if s.f.options.Insensitive { - name = strings.ToLower(name) - } - - if s.f.BlockMode { - s.f.lock.Lock() - defer s.f.lock.Unlock() - } - - if inSlice(name, s.keyList) { - if s.f.options.AllowShadows { - if err := s.keys[name].addShadow(val); err != nil { - return nil, err - } - } else { - s.keys[name].value = val - s.keysHash[name] = val - } - return s.keys[name], nil - } - - s.keyList = append(s.keyList, name) - s.keys[name] = newKey(s, name, val) - s.keysHash[name] = val - return s.keys[name], nil -} - -// NewBooleanKey creates a new boolean type key to given section. -func (s *Section) NewBooleanKey(name string) (*Key, error) { - key, err := s.NewKey(name, "true") - if err != nil { - return nil, err - } - - key.isBooleanType = true - return key, nil -} - -// GetKey returns key in section by given name. -func (s *Section) GetKey(name string) (*Key, error) { - if s.f.BlockMode { - s.f.lock.RLock() - } - if s.f.options.Insensitive { - name = strings.ToLower(name) - } - key := s.keys[name] - if s.f.BlockMode { - s.f.lock.RUnlock() - } - - if key == nil { - // Check if it is a child-section. - sname := s.name - for { - if i := strings.LastIndex(sname, "."); i > -1 { - sname = sname[:i] - sec, err := s.f.GetSection(sname) - if err != nil { - continue - } - return sec.GetKey(name) - } - break - } - return nil, fmt.Errorf("error when getting key of section %q: key %q not exists", s.name, name) - } - return key, nil -} - -// HasKey returns true if section contains a key with given name. -func (s *Section) HasKey(name string) bool { - key, _ := s.GetKey(name) - return key != nil -} - -// Deprecated: Use "HasKey" instead. -func (s *Section) Haskey(name string) bool { - return s.HasKey(name) -} - -// HasValue returns true if section contains given raw value. -func (s *Section) HasValue(value string) bool { - if s.f.BlockMode { - s.f.lock.RLock() - defer s.f.lock.RUnlock() - } - - for _, k := range s.keys { - if value == k.value { - return true - } - } - return false -} - -// Key assumes named Key exists in section and returns a zero-value when not. -func (s *Section) Key(name string) *Key { - key, err := s.GetKey(name) - if err != nil { - // It's OK here because the only possible error is empty key name, - // but if it's empty, this piece of code won't be executed. - key, _ = s.NewKey(name, "") - return key - } - return key -} - -// Keys returns list of keys of section. -func (s *Section) Keys() []*Key { - keys := make([]*Key, len(s.keyList)) - for i := range s.keyList { - keys[i] = s.Key(s.keyList[i]) - } - return keys -} - -// ParentKeys returns list of keys of parent section. -func (s *Section) ParentKeys() []*Key { - var parentKeys []*Key - sname := s.name - for { - if i := strings.LastIndex(sname, "."); i > -1 { - sname = sname[:i] - sec, err := s.f.GetSection(sname) - if err != nil { - continue - } - parentKeys = append(parentKeys, sec.Keys()...) - } else { - break - } - - } - return parentKeys -} - -// KeyStrings returns list of key names of section. -func (s *Section) KeyStrings() []string { - list := make([]string, len(s.keyList)) - copy(list, s.keyList) - return list -} - -// KeysHash returns keys hash consisting of names and values. -func (s *Section) KeysHash() map[string]string { - if s.f.BlockMode { - s.f.lock.RLock() - defer s.f.lock.RUnlock() - } - - hash := map[string]string{} - for key, value := range s.keysHash { - hash[key] = value - } - return hash -} - -// DeleteKey deletes a key from section. -func (s *Section) DeleteKey(name string) { - if s.f.BlockMode { - s.f.lock.Lock() - defer s.f.lock.Unlock() - } - - for i, k := range s.keyList { - if k == name { - s.keyList = append(s.keyList[:i], s.keyList[i+1:]...) - delete(s.keys, name) - delete(s.keysHash, name) - return - } - } -} - -// ChildSections returns a list of child sections of current section. -// For example, "[parent.child1]" and "[parent.child12]" are child sections -// of section "[parent]". -func (s *Section) ChildSections() []*Section { - prefix := s.name + "." - children := make([]*Section, 0, 3) - for _, name := range s.f.sectionList { - if strings.HasPrefix(name, prefix) { - children = append(children, s.f.sections[name]...) - } - } - return children -} diff --git a/vendor/github.com/go-ini/ini/struct.go b/vendor/github.com/go-ini/ini/struct.go deleted file mode 100644 index 9be40a9200681..0000000000000 --- a/vendor/github.com/go-ini/ini/struct.go +++ /dev/null @@ -1,729 +0,0 @@ -// Copyright 2014 Unknwon -// -// Licensed under the Apache License, Version 2.0 (the "License"): you may -// not use this file except in compliance with the License. You may obtain -// a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. - -package ini - -import ( - "bytes" - "errors" - "fmt" - "reflect" - "strings" - "time" - "unicode" -) - -// NameMapper represents a ini tag name mapper. -type NameMapper func(string) string - -// Built-in name getters. -var ( - // SnackCase converts to format SNACK_CASE. - SnackCase NameMapper = func(raw string) string { - newstr := make([]rune, 0, len(raw)) - for i, chr := range raw { - if isUpper := 'A' <= chr && chr <= 'Z'; isUpper { - if i > 0 { - newstr = append(newstr, '_') - } - } - newstr = append(newstr, unicode.ToUpper(chr)) - } - return string(newstr) - } - // TitleUnderscore converts to format title_underscore. - TitleUnderscore NameMapper = func(raw string) string { - newstr := make([]rune, 0, len(raw)) - for i, chr := range raw { - if isUpper := 'A' <= chr && chr <= 'Z'; isUpper { - if i > 0 { - newstr = append(newstr, '_') - } - chr -= 'A' - 'a' - } - newstr = append(newstr, chr) - } - return string(newstr) - } -) - -func (s *Section) parseFieldName(raw, actual string) string { - if len(actual) > 0 { - return actual - } - if s.f.NameMapper != nil { - return s.f.NameMapper(raw) - } - return raw -} - -func parseDelim(actual string) string { - if len(actual) > 0 { - return actual - } - return "," -} - -var reflectTime = reflect.TypeOf(time.Now()).Kind() - -// setSliceWithProperType sets proper values to slice based on its type. -func setSliceWithProperType(key *Key, field reflect.Value, delim string, allowShadow, isStrict bool) error { - var strs []string - if allowShadow { - strs = key.StringsWithShadows(delim) - } else { - strs = key.Strings(delim) - } - - numVals := len(strs) - if numVals == 0 { - return nil - } - - var vals interface{} - var err error - - sliceOf := field.Type().Elem().Kind() - switch sliceOf { - case reflect.String: - vals = strs - case reflect.Int: - vals, err = key.parseInts(strs, true, false) - case reflect.Int64: - vals, err = key.parseInt64s(strs, true, false) - case reflect.Uint: - vals, err = key.parseUints(strs, true, false) - case reflect.Uint64: - vals, err = key.parseUint64s(strs, true, false) - case reflect.Float64: - vals, err = key.parseFloat64s(strs, true, false) - case reflect.Bool: - vals, err = key.parseBools(strs, true, false) - case reflectTime: - vals, err = key.parseTimesFormat(time.RFC3339, strs, true, false) - default: - return fmt.Errorf("unsupported type '[]%s'", sliceOf) - } - if err != nil && isStrict { - return err - } - - slice := reflect.MakeSlice(field.Type(), numVals, numVals) - for i := 0; i < numVals; i++ { - switch sliceOf { - case reflect.String: - slice.Index(i).Set(reflect.ValueOf(vals.([]string)[i])) - case reflect.Int: - slice.Index(i).Set(reflect.ValueOf(vals.([]int)[i])) - case reflect.Int64: - slice.Index(i).Set(reflect.ValueOf(vals.([]int64)[i])) - case reflect.Uint: - slice.Index(i).Set(reflect.ValueOf(vals.([]uint)[i])) - case reflect.Uint64: - slice.Index(i).Set(reflect.ValueOf(vals.([]uint64)[i])) - case reflect.Float64: - slice.Index(i).Set(reflect.ValueOf(vals.([]float64)[i])) - case reflect.Bool: - slice.Index(i).Set(reflect.ValueOf(vals.([]bool)[i])) - case reflectTime: - slice.Index(i).Set(reflect.ValueOf(vals.([]time.Time)[i])) - } - } - field.Set(slice) - return nil -} - -func wrapStrictError(err error, isStrict bool) error { - if isStrict { - return err - } - return nil -} - -// setWithProperType sets proper value to field based on its type, -// but it does not return error for failing parsing, -// because we want to use default value that is already assigned to struct. -func setWithProperType(t reflect.Type, key *Key, field reflect.Value, delim string, allowShadow, isStrict bool) error { - vt := t - isPtr := t.Kind() == reflect.Ptr - if isPtr { - vt = t.Elem() - } - switch vt.Kind() { - case reflect.String: - stringVal := key.String() - if isPtr { - field.Set(reflect.ValueOf(&stringVal)) - } else if len(stringVal) > 0 { - field.SetString(key.String()) - } - case reflect.Bool: - boolVal, err := key.Bool() - if err != nil { - return wrapStrictError(err, isStrict) - } - if isPtr { - field.Set(reflect.ValueOf(&boolVal)) - } else { - field.SetBool(boolVal) - } - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - // ParseDuration will not return err for `0`, so check the type name - if vt.Name() == "Duration" { - durationVal, err := key.Duration() - if err != nil { - if intVal, err := key.Int64(); err == nil { - field.SetInt(intVal) - return nil - } - return wrapStrictError(err, isStrict) - } - if isPtr { - field.Set(reflect.ValueOf(&durationVal)) - } else if int64(durationVal) > 0 { - field.Set(reflect.ValueOf(durationVal)) - } - return nil - } - - intVal, err := key.Int64() - if err != nil { - return wrapStrictError(err, isStrict) - } - if isPtr { - pv := reflect.New(t.Elem()) - pv.Elem().SetInt(intVal) - field.Set(pv) - } else { - field.SetInt(intVal) - } - // byte is an alias for uint8, so supporting uint8 breaks support for byte - case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64: - durationVal, err := key.Duration() - // Skip zero value - if err == nil && uint64(durationVal) > 0 { - if isPtr { - field.Set(reflect.ValueOf(&durationVal)) - } else { - field.Set(reflect.ValueOf(durationVal)) - } - return nil - } - - uintVal, err := key.Uint64() - if err != nil { - return wrapStrictError(err, isStrict) - } - if isPtr { - pv := reflect.New(t.Elem()) - pv.Elem().SetUint(uintVal) - field.Set(pv) - } else { - field.SetUint(uintVal) - } - - case reflect.Float32, reflect.Float64: - floatVal, err := key.Float64() - if err != nil { - return wrapStrictError(err, isStrict) - } - if isPtr { - pv := reflect.New(t.Elem()) - pv.Elem().SetFloat(floatVal) - field.Set(pv) - } else { - field.SetFloat(floatVal) - } - case reflectTime: - timeVal, err := key.Time() - if err != nil { - return wrapStrictError(err, isStrict) - } - if isPtr { - field.Set(reflect.ValueOf(&timeVal)) - } else { - field.Set(reflect.ValueOf(timeVal)) - } - case reflect.Slice: - return setSliceWithProperType(key, field, delim, allowShadow, isStrict) - default: - return fmt.Errorf("unsupported type %q", t) - } - return nil -} - -func parseTagOptions(tag string) (rawName string, omitEmpty bool, allowShadow bool, allowNonUnique bool) { - opts := strings.SplitN(tag, ",", 4) - rawName = opts[0] - if len(opts) > 1 { - omitEmpty = opts[1] == "omitempty" - } - if len(opts) > 2 { - allowShadow = opts[2] == "allowshadow" - } - if len(opts) > 3 { - allowNonUnique = opts[3] == "nonunique" - } - return rawName, omitEmpty, allowShadow, allowNonUnique -} - -// mapToField maps the given value to the matching field of the given section. -// The sectionIndex is the index (if non unique sections are enabled) to which the value should be added. -func (s *Section) mapToField(val reflect.Value, isStrict bool, sectionIndex int) error { - if val.Kind() == reflect.Ptr { - val = val.Elem() - } - typ := val.Type() - - for i := 0; i < typ.NumField(); i++ { - field := val.Field(i) - tpField := typ.Field(i) - - tag := tpField.Tag.Get("ini") - if tag == "-" { - continue - } - - rawName, _, allowShadow, allowNonUnique := parseTagOptions(tag) - fieldName := s.parseFieldName(tpField.Name, rawName) - if len(fieldName) == 0 || !field.CanSet() { - continue - } - - isStruct := tpField.Type.Kind() == reflect.Struct - isStructPtr := tpField.Type.Kind() == reflect.Ptr && tpField.Type.Elem().Kind() == reflect.Struct - isAnonymous := tpField.Type.Kind() == reflect.Ptr && tpField.Anonymous - if isAnonymous { - field.Set(reflect.New(tpField.Type.Elem())) - } - - if isAnonymous || isStruct || isStructPtr { - if secs, err := s.f.SectionsByName(fieldName); err == nil { - if len(secs) <= sectionIndex { - return fmt.Errorf("there are not enough sections (%d <= %d) for the field %q", len(secs), sectionIndex, fieldName) - } - // Only set the field to non-nil struct value if we have a section for it. - // Otherwise, we end up with a non-nil struct ptr even though there is no data. - if isStructPtr && field.IsNil() { - field.Set(reflect.New(tpField.Type.Elem())) - } - if err = secs[sectionIndex].mapToField(field, isStrict, sectionIndex); err != nil { - return fmt.Errorf("map to field %q: %v", fieldName, err) - } - continue - } - } - - // Map non-unique sections - if allowNonUnique && tpField.Type.Kind() == reflect.Slice { - newField, err := s.mapToSlice(fieldName, field, isStrict) - if err != nil { - return fmt.Errorf("map to slice %q: %v", fieldName, err) - } - - field.Set(newField) - continue - } - - if key, err := s.GetKey(fieldName); err == nil { - delim := parseDelim(tpField.Tag.Get("delim")) - if err = setWithProperType(tpField.Type, key, field, delim, allowShadow, isStrict); err != nil { - return fmt.Errorf("set field %q: %v", fieldName, err) - } - } - } - return nil -} - -// mapToSlice maps all sections with the same name and returns the new value. -// The type of the Value must be a slice. -func (s *Section) mapToSlice(secName string, val reflect.Value, isStrict bool) (reflect.Value, error) { - secs, err := s.f.SectionsByName(secName) - if err != nil { - return reflect.Value{}, err - } - - typ := val.Type().Elem() - for i, sec := range secs { - elem := reflect.New(typ) - if err = sec.mapToField(elem, isStrict, i); err != nil { - return reflect.Value{}, fmt.Errorf("map to field from section %q: %v", secName, err) - } - - val = reflect.Append(val, elem.Elem()) - } - return val, nil -} - -// mapTo maps a section to object v. -func (s *Section) mapTo(v interface{}, isStrict bool) error { - typ := reflect.TypeOf(v) - val := reflect.ValueOf(v) - if typ.Kind() == reflect.Ptr { - typ = typ.Elem() - val = val.Elem() - } else { - return errors.New("not a pointer to a struct") - } - - if typ.Kind() == reflect.Slice { - newField, err := s.mapToSlice(s.name, val, isStrict) - if err != nil { - return err - } - - val.Set(newField) - return nil - } - - return s.mapToField(val, isStrict, 0) -} - -// MapTo maps section to given struct. -func (s *Section) MapTo(v interface{}) error { - return s.mapTo(v, false) -} - -// StrictMapTo maps section to given struct in strict mode, -// which returns all possible error including value parsing error. -func (s *Section) StrictMapTo(v interface{}) error { - return s.mapTo(v, true) -} - -// MapTo maps file to given struct. -func (f *File) MapTo(v interface{}) error { - return f.Section("").MapTo(v) -} - -// StrictMapTo maps file to given struct in strict mode, -// which returns all possible error including value parsing error. -func (f *File) StrictMapTo(v interface{}) error { - return f.Section("").StrictMapTo(v) -} - -// MapToWithMapper maps data sources to given struct with name mapper. -func MapToWithMapper(v interface{}, mapper NameMapper, source interface{}, others ...interface{}) error { - cfg, err := Load(source, others...) - if err != nil { - return err - } - cfg.NameMapper = mapper - return cfg.MapTo(v) -} - -// StrictMapToWithMapper maps data sources to given struct with name mapper in strict mode, -// which returns all possible error including value parsing error. -func StrictMapToWithMapper(v interface{}, mapper NameMapper, source interface{}, others ...interface{}) error { - cfg, err := Load(source, others...) - if err != nil { - return err - } - cfg.NameMapper = mapper - return cfg.StrictMapTo(v) -} - -// MapTo maps data sources to given struct. -func MapTo(v, source interface{}, others ...interface{}) error { - return MapToWithMapper(v, nil, source, others...) -} - -// StrictMapTo maps data sources to given struct in strict mode, -// which returns all possible error including value parsing error. -func StrictMapTo(v, source interface{}, others ...interface{}) error { - return StrictMapToWithMapper(v, nil, source, others...) -} - -// reflectSliceWithProperType does the opposite thing as setSliceWithProperType. -func reflectSliceWithProperType(key *Key, field reflect.Value, delim string, allowShadow bool) error { - slice := field.Slice(0, field.Len()) - if field.Len() == 0 { - return nil - } - sliceOf := field.Type().Elem().Kind() - - if allowShadow { - var keyWithShadows *Key - for i := 0; i < field.Len(); i++ { - var val string - switch sliceOf { - case reflect.String: - val = slice.Index(i).String() - case reflect.Int, reflect.Int64: - val = fmt.Sprint(slice.Index(i).Int()) - case reflect.Uint, reflect.Uint64: - val = fmt.Sprint(slice.Index(i).Uint()) - case reflect.Float64: - val = fmt.Sprint(slice.Index(i).Float()) - case reflect.Bool: - val = fmt.Sprint(slice.Index(i).Bool()) - case reflectTime: - val = slice.Index(i).Interface().(time.Time).Format(time.RFC3339) - default: - return fmt.Errorf("unsupported type '[]%s'", sliceOf) - } - - if i == 0 { - keyWithShadows = newKey(key.s, key.name, val) - } else { - _ = keyWithShadows.AddShadow(val) - } - } - key = keyWithShadows - return nil - } - - var buf bytes.Buffer - for i := 0; i < field.Len(); i++ { - switch sliceOf { - case reflect.String: - buf.WriteString(slice.Index(i).String()) - case reflect.Int, reflect.Int64: - buf.WriteString(fmt.Sprint(slice.Index(i).Int())) - case reflect.Uint, reflect.Uint64: - buf.WriteString(fmt.Sprint(slice.Index(i).Uint())) - case reflect.Float64: - buf.WriteString(fmt.Sprint(slice.Index(i).Float())) - case reflect.Bool: - buf.WriteString(fmt.Sprint(slice.Index(i).Bool())) - case reflectTime: - buf.WriteString(slice.Index(i).Interface().(time.Time).Format(time.RFC3339)) - default: - return fmt.Errorf("unsupported type '[]%s'", sliceOf) - } - buf.WriteString(delim) - } - key.SetValue(buf.String()[:buf.Len()-len(delim)]) - return nil -} - -// reflectWithProperType does the opposite thing as setWithProperType. -func reflectWithProperType(t reflect.Type, key *Key, field reflect.Value, delim string, allowShadow bool) error { - switch t.Kind() { - case reflect.String: - key.SetValue(field.String()) - case reflect.Bool: - key.SetValue(fmt.Sprint(field.Bool())) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - key.SetValue(fmt.Sprint(field.Int())) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - key.SetValue(fmt.Sprint(field.Uint())) - case reflect.Float32, reflect.Float64: - key.SetValue(fmt.Sprint(field.Float())) - case reflectTime: - key.SetValue(fmt.Sprint(field.Interface().(time.Time).Format(time.RFC3339))) - case reflect.Slice: - return reflectSliceWithProperType(key, field, delim, allowShadow) - case reflect.Ptr: - if !field.IsNil() { - return reflectWithProperType(t.Elem(), key, field.Elem(), delim, allowShadow) - } - default: - return fmt.Errorf("unsupported type %q", t) - } - return nil -} - -// CR: copied from encoding/json/encode.go with modifications of time.Time support. -// TODO: add more test coverage. -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 reflectTime: - t, ok := v.Interface().(time.Time) - return ok && t.IsZero() - } - return false -} - -// StructReflector is the interface implemented by struct types that can extract themselves into INI objects. -type StructReflector interface { - ReflectINIStruct(*File) error -} - -func (s *Section) reflectFrom(val reflect.Value) error { - if val.Kind() == reflect.Ptr { - val = val.Elem() - } - typ := val.Type() - - for i := 0; i < typ.NumField(); i++ { - if !val.Field(i).CanInterface() { - continue - } - - field := val.Field(i) - tpField := typ.Field(i) - - tag := tpField.Tag.Get("ini") - if tag == "-" { - continue - } - - rawName, omitEmpty, allowShadow, allowNonUnique := parseTagOptions(tag) - if omitEmpty && isEmptyValue(field) { - continue - } - - if r, ok := field.Interface().(StructReflector); ok { - return r.ReflectINIStruct(s.f) - } - - fieldName := s.parseFieldName(tpField.Name, rawName) - if len(fieldName) == 0 || !field.CanSet() { - continue - } - - if (tpField.Type.Kind() == reflect.Ptr && tpField.Anonymous) || - (tpField.Type.Kind() == reflect.Struct && tpField.Type.Name() != "Time") { - // Note: The only error here is section doesn't exist. - sec, err := s.f.GetSection(fieldName) - if err != nil { - // Note: fieldName can never be empty here, ignore error. - sec, _ = s.f.NewSection(fieldName) - } - - // Add comment from comment tag - if len(sec.Comment) == 0 { - sec.Comment = tpField.Tag.Get("comment") - } - - if err = sec.reflectFrom(field); err != nil { - return fmt.Errorf("reflect from field %q: %v", fieldName, err) - } - continue - } - - if allowNonUnique && tpField.Type.Kind() == reflect.Slice { - slice := field.Slice(0, field.Len()) - if field.Len() == 0 { - return nil - } - sliceOf := field.Type().Elem().Kind() - - for i := 0; i < field.Len(); i++ { - if sliceOf != reflect.Struct && sliceOf != reflect.Ptr { - return fmt.Errorf("field %q is not a slice of pointer or struct", fieldName) - } - - sec, err := s.f.NewSection(fieldName) - if err != nil { - return err - } - - // Add comment from comment tag - if len(sec.Comment) == 0 { - sec.Comment = tpField.Tag.Get("comment") - } - - if err := sec.reflectFrom(slice.Index(i)); err != nil { - return fmt.Errorf("reflect from field %q: %v", fieldName, err) - } - } - continue - } - - // Note: Same reason as section. - key, err := s.GetKey(fieldName) - if err != nil { - key, _ = s.NewKey(fieldName, "") - } - - // Add comment from comment tag - if len(key.Comment) == 0 { - key.Comment = tpField.Tag.Get("comment") - } - - delim := parseDelim(tpField.Tag.Get("delim")) - if err = reflectWithProperType(tpField.Type, key, field, delim, allowShadow); err != nil { - return fmt.Errorf("reflect field %q: %v", fieldName, err) - } - - } - return nil -} - -// ReflectFrom reflects section from given struct. It overwrites existing ones. -func (s *Section) ReflectFrom(v interface{}) error { - typ := reflect.TypeOf(v) - val := reflect.ValueOf(v) - - if s.name != DefaultSection && s.f.options.AllowNonUniqueSections && - (typ.Kind() == reflect.Slice || typ.Kind() == reflect.Ptr) { - // Clear sections to make sure none exists before adding the new ones - s.f.DeleteSection(s.name) - - if typ.Kind() == reflect.Ptr { - sec, err := s.f.NewSection(s.name) - if err != nil { - return err - } - return sec.reflectFrom(val.Elem()) - } - - slice := val.Slice(0, val.Len()) - sliceOf := val.Type().Elem().Kind() - if sliceOf != reflect.Ptr { - return fmt.Errorf("not a slice of pointers") - } - - for i := 0; i < slice.Len(); i++ { - sec, err := s.f.NewSection(s.name) - if err != nil { - return err - } - - err = sec.reflectFrom(slice.Index(i)) - if err != nil { - return fmt.Errorf("reflect from %dth field: %v", i, err) - } - } - - return nil - } - - if typ.Kind() == reflect.Ptr { - val = val.Elem() - } else { - return errors.New("not a pointer to a struct") - } - - return s.reflectFrom(val) -} - -// ReflectFrom reflects file from given struct. -func (f *File) ReflectFrom(v interface{}) error { - return f.Section("").ReflectFrom(v) -} - -// ReflectFromWithMapper reflects data sources from given struct with name mapper. -func ReflectFromWithMapper(cfg *File, v interface{}, mapper NameMapper) error { - cfg.NameMapper = mapper - return cfg.ReflectFrom(v) -} - -// ReflectFrom reflects data sources from given struct. -func ReflectFrom(cfg *File, v interface{}) error { - return ReflectFromWithMapper(cfg, v, nil) -} diff --git a/vendor/github.com/json-iterator/go/.codecov.yml b/vendor/github.com/json-iterator/go/.codecov.yml new file mode 100644 index 0000000000000..955dc0be5fa67 --- /dev/null +++ b/vendor/github.com/json-iterator/go/.codecov.yml @@ -0,0 +1,3 @@ +ignore: + - "output_tests/.*" + diff --git a/vendor/github.com/json-iterator/go/.gitignore b/vendor/github.com/json-iterator/go/.gitignore new file mode 100644 index 0000000000000..15556530a8542 --- /dev/null +++ b/vendor/github.com/json-iterator/go/.gitignore @@ -0,0 +1,4 @@ +/vendor +/bug_test.go +/coverage.txt +/.idea diff --git a/vendor/github.com/json-iterator/go/.travis.yml b/vendor/github.com/json-iterator/go/.travis.yml new file mode 100644 index 0000000000000..449e67cd01acb --- /dev/null +++ b/vendor/github.com/json-iterator/go/.travis.yml @@ -0,0 +1,14 @@ +language: go + +go: + - 1.8.x + - 1.x + +before_install: + - go get -t -v ./... + +script: + - ./test.sh + +after_success: + - bash <(curl -s https://codecov.io/bash) diff --git a/vendor/github.com/json-iterator/go/Gopkg.lock b/vendor/github.com/json-iterator/go/Gopkg.lock new file mode 100644 index 0000000000000..c8a9fbb3871b0 --- /dev/null +++ b/vendor/github.com/json-iterator/go/Gopkg.lock @@ -0,0 +1,21 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + name = "github.com/modern-go/concurrent" + packages = ["."] + revision = "e0a39a4cb4216ea8db28e22a69f4ec25610d513a" + version = "1.0.0" + +[[projects]] + name = "github.com/modern-go/reflect2" + packages = ["."] + revision = "4b7aa43c6742a2c18fdef89dd197aaae7dac7ccd" + version = "1.0.1" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + inputs-digest = "ea54a775e5a354cb015502d2e7aa4b74230fc77e894f34a838b268c25ec8eeb8" + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/vendor/github.com/json-iterator/go/Gopkg.toml b/vendor/github.com/json-iterator/go/Gopkg.toml new file mode 100644 index 0000000000000..313a0f887b6f4 --- /dev/null +++ b/vendor/github.com/json-iterator/go/Gopkg.toml @@ -0,0 +1,26 @@ +# Gopkg.toml example +# +# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md +# for detailed Gopkg.toml documentation. +# +# required = ["github.com/user/thing/cmd/thing"] +# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] +# +# [[constraint]] +# name = "github.com/user/project" +# version = "1.0.0" +# +# [[constraint]] +# name = "github.com/user/project2" +# branch = "dev" +# source = "github.com/myfork/project2" +# +# [[override]] +# name = "github.com/x/y" +# version = "2.4.0" + +ignored = ["github.com/davecgh/go-spew*","github.com/google/gofuzz*","github.com/stretchr/testify*"] + +[[constraint]] + name = "github.com/modern-go/reflect2" + version = "1.0.1" diff --git a/vendor/github.com/json-iterator/go/LICENSE b/vendor/github.com/json-iterator/go/LICENSE new file mode 100644 index 0000000000000..2cf4f5ab28e9c --- /dev/null +++ b/vendor/github.com/json-iterator/go/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016 json-iterator + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/json-iterator/go/README.md b/vendor/github.com/json-iterator/go/README.md new file mode 100644 index 0000000000000..50d56ffbf07e5 --- /dev/null +++ b/vendor/github.com/json-iterator/go/README.md @@ -0,0 +1,87 @@ +[![Sourcegraph](https://sourcegraph.com/github.com/json-iterator/go/-/badge.svg)](https://sourcegraph.com/github.com/json-iterator/go?badge) +[![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](http://godoc.org/github.com/json-iterator/go) +[![Build Status](https://travis-ci.org/json-iterator/go.svg?branch=master)](https://travis-ci.org/json-iterator/go) +[![codecov](https://codecov.io/gh/json-iterator/go/branch/master/graph/badge.svg)](https://codecov.io/gh/json-iterator/go) +[![rcard](https://goreportcard.com/badge/github.com/json-iterator/go)](https://goreportcard.com/report/github.com/json-iterator/go) +[![License](http://img.shields.io/badge/license-mit-blue.svg?style=flat-square)](https://raw.githubusercontent.com/json-iterator/go/master/LICENSE) +[![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/json-iterator/Lobby) + +A high-performance 100% compatible drop-in replacement of "encoding/json" + +You can also use thrift like JSON using [thrift-iterator](https://github.com/thrift-iterator/go) + +# Benchmark + +![benchmark](http://jsoniter.com/benchmarks/go-benchmark.png) + +Source code: https://github.com/json-iterator/go-benchmark/blob/master/src/github.com/json-iterator/go-benchmark/benchmark_medium_payload_test.go + +Raw Result (easyjson requires static code generation) + +| | ns/op | allocation bytes | allocation times | +| --- | --- | --- | --- | +| std decode | 35510 ns/op | 1960 B/op | 99 allocs/op | +| easyjson decode | 8499 ns/op | 160 B/op | 4 allocs/op | +| jsoniter decode | 5623 ns/op | 160 B/op | 3 allocs/op | +| std encode | 2213 ns/op | 712 B/op | 5 allocs/op | +| easyjson encode | 883 ns/op | 576 B/op | 3 allocs/op | +| jsoniter encode | 837 ns/op | 384 B/op | 4 allocs/op | + +Always benchmark with your own workload. +The result depends heavily on the data input. + +# Usage + +100% compatibility with standard lib + +Replace + +```go +import "encoding/json" +json.Marshal(&data) +``` + +with + +```go +import "github.com/json-iterator/go" + +var json = jsoniter.ConfigCompatibleWithStandardLibrary +json.Marshal(&data) +``` + +Replace + +```go +import "encoding/json" +json.Unmarshal(input, &data) +``` + +with + +```go +import "github.com/json-iterator/go" + +var json = jsoniter.ConfigCompatibleWithStandardLibrary +json.Unmarshal(input, &data) +``` + +[More documentation](http://jsoniter.com/migrate-from-go-std.html) + +# How to get + +``` +go get github.com/json-iterator/go +``` + +# Contribution Welcomed ! + +Contributors + +* [thockin](https://github.com/thockin) +* [mattn](https://github.com/mattn) +* [cch123](https://github.com/cch123) +* [Oleg Shaldybin](https://github.com/olegshaldybin) +* [Jason Toffaletti](https://github.com/toffaletti) + +Report issue or pull request, or email taowen@gmail.com, or [![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/json-iterator/Lobby) diff --git a/vendor/github.com/json-iterator/go/adapter.go b/vendor/github.com/json-iterator/go/adapter.go new file mode 100644 index 0000000000000..92d2cc4a3dd5c --- /dev/null +++ b/vendor/github.com/json-iterator/go/adapter.go @@ -0,0 +1,150 @@ +package jsoniter + +import ( + "bytes" + "io" +) + +// RawMessage to make replace json with jsoniter +type RawMessage []byte + +// Unmarshal adapts to json/encoding Unmarshal API +// +// Unmarshal parses the JSON-encoded data and stores the result in the value pointed to by v. +// Refer to https://godoc.org/encoding/json#Unmarshal for more information +func Unmarshal(data []byte, v interface{}) error { + return ConfigDefault.Unmarshal(data, v) +} + +// UnmarshalFromString is a convenient method to read from string instead of []byte +func UnmarshalFromString(str string, v interface{}) error { + return ConfigDefault.UnmarshalFromString(str, v) +} + +// Get quick method to get value from deeply nested JSON structure +func Get(data []byte, path ...interface{}) Any { + return ConfigDefault.Get(data, path...) +} + +// Marshal adapts to json/encoding Marshal API +// +// Marshal returns the JSON encoding of v, adapts to json/encoding Marshal API +// Refer to https://godoc.org/encoding/json#Marshal for more information +func Marshal(v interface{}) ([]byte, error) { + return ConfigDefault.Marshal(v) +} + +// MarshalIndent same as json.MarshalIndent. Prefix is not supported. +func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) { + return ConfigDefault.MarshalIndent(v, prefix, indent) +} + +// MarshalToString convenient method to write as string instead of []byte +func MarshalToString(v interface{}) (string, error) { + return ConfigDefault.MarshalToString(v) +} + +// NewDecoder adapts to json/stream NewDecoder API. +// +// NewDecoder returns a new decoder that reads from r. +// +// Instead of a json/encoding Decoder, an Decoder is returned +// Refer to https://godoc.org/encoding/json#NewDecoder for more information +func NewDecoder(reader io.Reader) *Decoder { + return ConfigDefault.NewDecoder(reader) +} + +// Decoder reads and decodes JSON values from an input stream. +// Decoder provides identical APIs with json/stream Decoder (Token() and UseNumber() are in progress) +type Decoder struct { + iter *Iterator +} + +// Decode decode JSON into interface{} +func (adapter *Decoder) Decode(obj interface{}) error { + if adapter.iter.head == adapter.iter.tail && adapter.iter.reader != nil { + if !adapter.iter.loadMore() { + return io.EOF + } + } + adapter.iter.ReadVal(obj) + err := adapter.iter.Error + if err == io.EOF { + return nil + } + return adapter.iter.Error +} + +// More is there more? +func (adapter *Decoder) More() bool { + iter := adapter.iter + if iter.Error != nil { + return false + } + c := iter.nextToken() + if c == 0 { + return false + } + iter.unreadByte() + return c != ']' && c != '}' +} + +// Buffered remaining buffer +func (adapter *Decoder) Buffered() io.Reader { + remaining := adapter.iter.buf[adapter.iter.head:adapter.iter.tail] + return bytes.NewReader(remaining) +} + +// UseNumber causes the Decoder to unmarshal a number into an interface{} as a +// Number instead of as a float64. +func (adapter *Decoder) UseNumber() { + cfg := adapter.iter.cfg.configBeforeFrozen + cfg.UseNumber = true + adapter.iter.cfg = cfg.frozeWithCacheReuse(adapter.iter.cfg.extraExtensions) +} + +// DisallowUnknownFields causes the Decoder to return an error when the destination +// is a struct and the input contains object keys which do not match any +// non-ignored, exported fields in the destination. +func (adapter *Decoder) DisallowUnknownFields() { + cfg := adapter.iter.cfg.configBeforeFrozen + cfg.DisallowUnknownFields = true + adapter.iter.cfg = cfg.frozeWithCacheReuse(adapter.iter.cfg.extraExtensions) +} + +// NewEncoder same as json.NewEncoder +func NewEncoder(writer io.Writer) *Encoder { + return ConfigDefault.NewEncoder(writer) +} + +// Encoder same as json.Encoder +type Encoder struct { + stream *Stream +} + +// Encode encode interface{} as JSON to io.Writer +func (adapter *Encoder) Encode(val interface{}) error { + adapter.stream.WriteVal(val) + adapter.stream.WriteRaw("\n") + adapter.stream.Flush() + return adapter.stream.Error +} + +// SetIndent set the indention. Prefix is not supported +func (adapter *Encoder) SetIndent(prefix, indent string) { + config := adapter.stream.cfg.configBeforeFrozen + config.IndentionStep = len(indent) + adapter.stream.cfg = config.frozeWithCacheReuse(adapter.stream.cfg.extraExtensions) +} + +// SetEscapeHTML escape html by default, set to false to disable +func (adapter *Encoder) SetEscapeHTML(escapeHTML bool) { + config := adapter.stream.cfg.configBeforeFrozen + config.EscapeHTML = escapeHTML + adapter.stream.cfg = config.frozeWithCacheReuse(adapter.stream.cfg.extraExtensions) +} + +// Valid reports whether data is a valid JSON encoding. +func Valid(data []byte) bool { + return ConfigDefault.Valid(data) +} diff --git a/vendor/github.com/json-iterator/go/any.go b/vendor/github.com/json-iterator/go/any.go new file mode 100644 index 0000000000000..f6b8aeab0a12d --- /dev/null +++ b/vendor/github.com/json-iterator/go/any.go @@ -0,0 +1,325 @@ +package jsoniter + +import ( + "errors" + "fmt" + "github.com/modern-go/reflect2" + "io" + "reflect" + "strconv" + "unsafe" +) + +// Any generic object representation. +// The lazy json implementation holds []byte and parse lazily. +type Any interface { + LastError() error + ValueType() ValueType + MustBeValid() Any + ToBool() bool + ToInt() int + ToInt32() int32 + ToInt64() int64 + ToUint() uint + ToUint32() uint32 + ToUint64() uint64 + ToFloat32() float32 + ToFloat64() float64 + ToString() string + ToVal(val interface{}) + Get(path ...interface{}) Any + Size() int + Keys() []string + GetInterface() interface{} + WriteTo(stream *Stream) +} + +type baseAny struct{} + +func (any *baseAny) Get(path ...interface{}) Any { + return &invalidAny{baseAny{}, fmt.Errorf("GetIndex %v from simple value", path)} +} + +func (any *baseAny) Size() int { + return 0 +} + +func (any *baseAny) Keys() []string { + return []string{} +} + +func (any *baseAny) ToVal(obj interface{}) { + panic("not implemented") +} + +// WrapInt32 turn int32 into Any interface +func WrapInt32(val int32) Any { + return &int32Any{baseAny{}, val} +} + +// WrapInt64 turn int64 into Any interface +func WrapInt64(val int64) Any { + return &int64Any{baseAny{}, val} +} + +// WrapUint32 turn uint32 into Any interface +func WrapUint32(val uint32) Any { + return &uint32Any{baseAny{}, val} +} + +// WrapUint64 turn uint64 into Any interface +func WrapUint64(val uint64) Any { + return &uint64Any{baseAny{}, val} +} + +// WrapFloat64 turn float64 into Any interface +func WrapFloat64(val float64) Any { + return &floatAny{baseAny{}, val} +} + +// WrapString turn string into Any interface +func WrapString(val string) Any { + return &stringAny{baseAny{}, val} +} + +// Wrap turn a go object into Any interface +func Wrap(val interface{}) Any { + if val == nil { + return &nilAny{} + } + asAny, isAny := val.(Any) + if isAny { + return asAny + } + typ := reflect2.TypeOf(val) + switch typ.Kind() { + case reflect.Slice: + return wrapArray(val) + case reflect.Struct: + return wrapStruct(val) + case reflect.Map: + return wrapMap(val) + case reflect.String: + return WrapString(val.(string)) + case reflect.Int: + if strconv.IntSize == 32 { + return WrapInt32(int32(val.(int))) + } + return WrapInt64(int64(val.(int))) + case reflect.Int8: + return WrapInt32(int32(val.(int8))) + case reflect.Int16: + return WrapInt32(int32(val.(int16))) + case reflect.Int32: + return WrapInt32(val.(int32)) + case reflect.Int64: + return WrapInt64(val.(int64)) + case reflect.Uint: + if strconv.IntSize == 32 { + return WrapUint32(uint32(val.(uint))) + } + return WrapUint64(uint64(val.(uint))) + case reflect.Uintptr: + if ptrSize == 32 { + return WrapUint32(uint32(val.(uintptr))) + } + return WrapUint64(uint64(val.(uintptr))) + case reflect.Uint8: + return WrapUint32(uint32(val.(uint8))) + case reflect.Uint16: + return WrapUint32(uint32(val.(uint16))) + case reflect.Uint32: + return WrapUint32(uint32(val.(uint32))) + case reflect.Uint64: + return WrapUint64(val.(uint64)) + case reflect.Float32: + return WrapFloat64(float64(val.(float32))) + case reflect.Float64: + return WrapFloat64(val.(float64)) + case reflect.Bool: + if val.(bool) == true { + return &trueAny{} + } + return &falseAny{} + } + return &invalidAny{baseAny{}, fmt.Errorf("unsupported type: %v", typ)} +} + +// ReadAny read next JSON element as an Any object. It is a better json.RawMessage. +func (iter *Iterator) ReadAny() Any { + return iter.readAny() +} + +func (iter *Iterator) readAny() Any { + c := iter.nextToken() + switch c { + case '"': + iter.unreadByte() + return &stringAny{baseAny{}, iter.ReadString()} + case 'n': + iter.skipThreeBytes('u', 'l', 'l') // null + return &nilAny{} + case 't': + iter.skipThreeBytes('r', 'u', 'e') // true + return &trueAny{} + case 'f': + iter.skipFourBytes('a', 'l', 's', 'e') // false + return &falseAny{} + case '{': + return iter.readObjectAny() + case '[': + return iter.readArrayAny() + case '-': + return iter.readNumberAny(false) + case 0: + return &invalidAny{baseAny{}, errors.New("input is empty")} + default: + return iter.readNumberAny(true) + } +} + +func (iter *Iterator) readNumberAny(positive bool) Any { + iter.startCapture(iter.head - 1) + iter.skipNumber() + lazyBuf := iter.stopCapture() + return &numberLazyAny{baseAny{}, iter.cfg, lazyBuf, nil} +} + +func (iter *Iterator) readObjectAny() Any { + iter.startCapture(iter.head - 1) + iter.skipObject() + lazyBuf := iter.stopCapture() + return &objectLazyAny{baseAny{}, iter.cfg, lazyBuf, nil} +} + +func (iter *Iterator) readArrayAny() Any { + iter.startCapture(iter.head - 1) + iter.skipArray() + lazyBuf := iter.stopCapture() + return &arrayLazyAny{baseAny{}, iter.cfg, lazyBuf, nil} +} + +func locateObjectField(iter *Iterator, target string) []byte { + var found []byte + iter.ReadObjectCB(func(iter *Iterator, field string) bool { + if field == target { + found = iter.SkipAndReturnBytes() + return false + } + iter.Skip() + return true + }) + return found +} + +func locateArrayElement(iter *Iterator, target int) []byte { + var found []byte + n := 0 + iter.ReadArrayCB(func(iter *Iterator) bool { + if n == target { + found = iter.SkipAndReturnBytes() + return false + } + iter.Skip() + n++ + return true + }) + return found +} + +func locatePath(iter *Iterator, path []interface{}) Any { + for i, pathKeyObj := range path { + switch pathKey := pathKeyObj.(type) { + case string: + valueBytes := locateObjectField(iter, pathKey) + if valueBytes == nil { + return newInvalidAny(path[i:]) + } + iter.ResetBytes(valueBytes) + case int: + valueBytes := locateArrayElement(iter, pathKey) + if valueBytes == nil { + return newInvalidAny(path[i:]) + } + iter.ResetBytes(valueBytes) + case int32: + if '*' == pathKey { + return iter.readAny().Get(path[i:]...) + } + return newInvalidAny(path[i:]) + default: + return newInvalidAny(path[i:]) + } + } + if iter.Error != nil && iter.Error != io.EOF { + return &invalidAny{baseAny{}, iter.Error} + } + return iter.readAny() +} + +var anyType = reflect2.TypeOfPtr((*Any)(nil)).Elem() + +func createDecoderOfAny(ctx *ctx, typ reflect2.Type) ValDecoder { + if typ == anyType { + return &directAnyCodec{} + } + if typ.Implements(anyType) { + return &anyCodec{ + valType: typ, + } + } + return nil +} + +func createEncoderOfAny(ctx *ctx, typ reflect2.Type) ValEncoder { + if typ == anyType { + return &directAnyCodec{} + } + if typ.Implements(anyType) { + return &anyCodec{ + valType: typ, + } + } + return nil +} + +type anyCodec struct { + valType reflect2.Type +} + +func (codec *anyCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { + panic("not implemented") +} + +func (codec *anyCodec) Encode(ptr unsafe.Pointer, stream *Stream) { + obj := codec.valType.UnsafeIndirect(ptr) + any := obj.(Any) + any.WriteTo(stream) +} + +func (codec *anyCodec) IsEmpty(ptr unsafe.Pointer) bool { + obj := codec.valType.UnsafeIndirect(ptr) + any := obj.(Any) + return any.Size() == 0 +} + +type directAnyCodec struct { +} + +func (codec *directAnyCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { + *(*Any)(ptr) = iter.readAny() +} + +func (codec *directAnyCodec) Encode(ptr unsafe.Pointer, stream *Stream) { + any := *(*Any)(ptr) + if any == nil { + stream.WriteNil() + return + } + any.WriteTo(stream) +} + +func (codec *directAnyCodec) IsEmpty(ptr unsafe.Pointer) bool { + any := *(*Any)(ptr) + return any.Size() == 0 +} diff --git a/vendor/github.com/json-iterator/go/any_array.go b/vendor/github.com/json-iterator/go/any_array.go new file mode 100644 index 0000000000000..0449e9aa428ae --- /dev/null +++ b/vendor/github.com/json-iterator/go/any_array.go @@ -0,0 +1,278 @@ +package jsoniter + +import ( + "reflect" + "unsafe" +) + +type arrayLazyAny struct { + baseAny + cfg *frozenConfig + buf []byte + err error +} + +func (any *arrayLazyAny) ValueType() ValueType { + return ArrayValue +} + +func (any *arrayLazyAny) MustBeValid() Any { + return any +} + +func (any *arrayLazyAny) LastError() error { + return any.err +} + +func (any *arrayLazyAny) ToBool() bool { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + return iter.ReadArray() +} + +func (any *arrayLazyAny) ToInt() int { + if any.ToBool() { + return 1 + } + return 0 +} + +func (any *arrayLazyAny) ToInt32() int32 { + if any.ToBool() { + return 1 + } + return 0 +} + +func (any *arrayLazyAny) ToInt64() int64 { + if any.ToBool() { + return 1 + } + return 0 +} + +func (any *arrayLazyAny) ToUint() uint { + if any.ToBool() { + return 1 + } + return 0 +} + +func (any *arrayLazyAny) ToUint32() uint32 { + if any.ToBool() { + return 1 + } + return 0 +} + +func (any *arrayLazyAny) ToUint64() uint64 { + if any.ToBool() { + return 1 + } + return 0 +} + +func (any *arrayLazyAny) ToFloat32() float32 { + if any.ToBool() { + return 1 + } + return 0 +} + +func (any *arrayLazyAny) ToFloat64() float64 { + if any.ToBool() { + return 1 + } + return 0 +} + +func (any *arrayLazyAny) ToString() string { + return *(*string)(unsafe.Pointer(&any.buf)) +} + +func (any *arrayLazyAny) ToVal(val interface{}) { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + iter.ReadVal(val) +} + +func (any *arrayLazyAny) Get(path ...interface{}) Any { + if len(path) == 0 { + return any + } + switch firstPath := path[0].(type) { + case int: + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + valueBytes := locateArrayElement(iter, firstPath) + if valueBytes == nil { + return newInvalidAny(path) + } + iter.ResetBytes(valueBytes) + return locatePath(iter, path[1:]) + case int32: + if '*' == firstPath { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + arr := make([]Any, 0) + iter.ReadArrayCB(func(iter *Iterator) bool { + found := iter.readAny().Get(path[1:]...) + if found.ValueType() != InvalidValue { + arr = append(arr, found) + } + return true + }) + return wrapArray(arr) + } + return newInvalidAny(path) + default: + return newInvalidAny(path) + } +} + +func (any *arrayLazyAny) Size() int { + size := 0 + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + iter.ReadArrayCB(func(iter *Iterator) bool { + size++ + iter.Skip() + return true + }) + return size +} + +func (any *arrayLazyAny) WriteTo(stream *Stream) { + stream.Write(any.buf) +} + +func (any *arrayLazyAny) GetInterface() interface{} { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + return iter.Read() +} + +type arrayAny struct { + baseAny + val reflect.Value +} + +func wrapArray(val interface{}) *arrayAny { + return &arrayAny{baseAny{}, reflect.ValueOf(val)} +} + +func (any *arrayAny) ValueType() ValueType { + return ArrayValue +} + +func (any *arrayAny) MustBeValid() Any { + return any +} + +func (any *arrayAny) LastError() error { + return nil +} + +func (any *arrayAny) ToBool() bool { + return any.val.Len() != 0 +} + +func (any *arrayAny) ToInt() int { + if any.val.Len() == 0 { + return 0 + } + return 1 +} + +func (any *arrayAny) ToInt32() int32 { + if any.val.Len() == 0 { + return 0 + } + return 1 +} + +func (any *arrayAny) ToInt64() int64 { + if any.val.Len() == 0 { + return 0 + } + return 1 +} + +func (any *arrayAny) ToUint() uint { + if any.val.Len() == 0 { + return 0 + } + return 1 +} + +func (any *arrayAny) ToUint32() uint32 { + if any.val.Len() == 0 { + return 0 + } + return 1 +} + +func (any *arrayAny) ToUint64() uint64 { + if any.val.Len() == 0 { + return 0 + } + return 1 +} + +func (any *arrayAny) ToFloat32() float32 { + if any.val.Len() == 0 { + return 0 + } + return 1 +} + +func (any *arrayAny) ToFloat64() float64 { + if any.val.Len() == 0 { + return 0 + } + return 1 +} + +func (any *arrayAny) ToString() string { + str, _ := MarshalToString(any.val.Interface()) + return str +} + +func (any *arrayAny) Get(path ...interface{}) Any { + if len(path) == 0 { + return any + } + switch firstPath := path[0].(type) { + case int: + if firstPath < 0 || firstPath >= any.val.Len() { + return newInvalidAny(path) + } + return Wrap(any.val.Index(firstPath).Interface()) + case int32: + if '*' == firstPath { + mappedAll := make([]Any, 0) + for i := 0; i < any.val.Len(); i++ { + mapped := Wrap(any.val.Index(i).Interface()).Get(path[1:]...) + if mapped.ValueType() != InvalidValue { + mappedAll = append(mappedAll, mapped) + } + } + return wrapArray(mappedAll) + } + return newInvalidAny(path) + default: + return newInvalidAny(path) + } +} + +func (any *arrayAny) Size() int { + return any.val.Len() +} + +func (any *arrayAny) WriteTo(stream *Stream) { + stream.WriteVal(any.val) +} + +func (any *arrayAny) GetInterface() interface{} { + return any.val.Interface() +} diff --git a/vendor/github.com/json-iterator/go/any_bool.go b/vendor/github.com/json-iterator/go/any_bool.go new file mode 100644 index 0000000000000..9452324af5b17 --- /dev/null +++ b/vendor/github.com/json-iterator/go/any_bool.go @@ -0,0 +1,137 @@ +package jsoniter + +type trueAny struct { + baseAny +} + +func (any *trueAny) LastError() error { + return nil +} + +func (any *trueAny) ToBool() bool { + return true +} + +func (any *trueAny) ToInt() int { + return 1 +} + +func (any *trueAny) ToInt32() int32 { + return 1 +} + +func (any *trueAny) ToInt64() int64 { + return 1 +} + +func (any *trueAny) ToUint() uint { + return 1 +} + +func (any *trueAny) ToUint32() uint32 { + return 1 +} + +func (any *trueAny) ToUint64() uint64 { + return 1 +} + +func (any *trueAny) ToFloat32() float32 { + return 1 +} + +func (any *trueAny) ToFloat64() float64 { + return 1 +} + +func (any *trueAny) ToString() string { + return "true" +} + +func (any *trueAny) WriteTo(stream *Stream) { + stream.WriteTrue() +} + +func (any *trueAny) Parse() *Iterator { + return nil +} + +func (any *trueAny) GetInterface() interface{} { + return true +} + +func (any *trueAny) ValueType() ValueType { + return BoolValue +} + +func (any *trueAny) MustBeValid() Any { + return any +} + +type falseAny struct { + baseAny +} + +func (any *falseAny) LastError() error { + return nil +} + +func (any *falseAny) ToBool() bool { + return false +} + +func (any *falseAny) ToInt() int { + return 0 +} + +func (any *falseAny) ToInt32() int32 { + return 0 +} + +func (any *falseAny) ToInt64() int64 { + return 0 +} + +func (any *falseAny) ToUint() uint { + return 0 +} + +func (any *falseAny) ToUint32() uint32 { + return 0 +} + +func (any *falseAny) ToUint64() uint64 { + return 0 +} + +func (any *falseAny) ToFloat32() float32 { + return 0 +} + +func (any *falseAny) ToFloat64() float64 { + return 0 +} + +func (any *falseAny) ToString() string { + return "false" +} + +func (any *falseAny) WriteTo(stream *Stream) { + stream.WriteFalse() +} + +func (any *falseAny) Parse() *Iterator { + return nil +} + +func (any *falseAny) GetInterface() interface{} { + return false +} + +func (any *falseAny) ValueType() ValueType { + return BoolValue +} + +func (any *falseAny) MustBeValid() Any { + return any +} diff --git a/vendor/github.com/json-iterator/go/any_float.go b/vendor/github.com/json-iterator/go/any_float.go new file mode 100644 index 0000000000000..35fdb09497fa8 --- /dev/null +++ b/vendor/github.com/json-iterator/go/any_float.go @@ -0,0 +1,83 @@ +package jsoniter + +import ( + "strconv" +) + +type floatAny struct { + baseAny + val float64 +} + +func (any *floatAny) Parse() *Iterator { + return nil +} + +func (any *floatAny) ValueType() ValueType { + return NumberValue +} + +func (any *floatAny) MustBeValid() Any { + return any +} + +func (any *floatAny) LastError() error { + return nil +} + +func (any *floatAny) ToBool() bool { + return any.ToFloat64() != 0 +} + +func (any *floatAny) ToInt() int { + return int(any.val) +} + +func (any *floatAny) ToInt32() int32 { + return int32(any.val) +} + +func (any *floatAny) ToInt64() int64 { + return int64(any.val) +} + +func (any *floatAny) ToUint() uint { + if any.val > 0 { + return uint(any.val) + } + return 0 +} + +func (any *floatAny) ToUint32() uint32 { + if any.val > 0 { + return uint32(any.val) + } + return 0 +} + +func (any *floatAny) ToUint64() uint64 { + if any.val > 0 { + return uint64(any.val) + } + return 0 +} + +func (any *floatAny) ToFloat32() float32 { + return float32(any.val) +} + +func (any *floatAny) ToFloat64() float64 { + return any.val +} + +func (any *floatAny) ToString() string { + return strconv.FormatFloat(any.val, 'E', -1, 64) +} + +func (any *floatAny) WriteTo(stream *Stream) { + stream.WriteFloat64(any.val) +} + +func (any *floatAny) GetInterface() interface{} { + return any.val +} diff --git a/vendor/github.com/json-iterator/go/any_int32.go b/vendor/github.com/json-iterator/go/any_int32.go new file mode 100644 index 0000000000000..1b56f399150d9 --- /dev/null +++ b/vendor/github.com/json-iterator/go/any_int32.go @@ -0,0 +1,74 @@ +package jsoniter + +import ( + "strconv" +) + +type int32Any struct { + baseAny + val int32 +} + +func (any *int32Any) LastError() error { + return nil +} + +func (any *int32Any) ValueType() ValueType { + return NumberValue +} + +func (any *int32Any) MustBeValid() Any { + return any +} + +func (any *int32Any) ToBool() bool { + return any.val != 0 +} + +func (any *int32Any) ToInt() int { + return int(any.val) +} + +func (any *int32Any) ToInt32() int32 { + return any.val +} + +func (any *int32Any) ToInt64() int64 { + return int64(any.val) +} + +func (any *int32Any) ToUint() uint { + return uint(any.val) +} + +func (any *int32Any) ToUint32() uint32 { + return uint32(any.val) +} + +func (any *int32Any) ToUint64() uint64 { + return uint64(any.val) +} + +func (any *int32Any) ToFloat32() float32 { + return float32(any.val) +} + +func (any *int32Any) ToFloat64() float64 { + return float64(any.val) +} + +func (any *int32Any) ToString() string { + return strconv.FormatInt(int64(any.val), 10) +} + +func (any *int32Any) WriteTo(stream *Stream) { + stream.WriteInt32(any.val) +} + +func (any *int32Any) Parse() *Iterator { + return nil +} + +func (any *int32Any) GetInterface() interface{} { + return any.val +} diff --git a/vendor/github.com/json-iterator/go/any_int64.go b/vendor/github.com/json-iterator/go/any_int64.go new file mode 100644 index 0000000000000..c440d72b6d3ae --- /dev/null +++ b/vendor/github.com/json-iterator/go/any_int64.go @@ -0,0 +1,74 @@ +package jsoniter + +import ( + "strconv" +) + +type int64Any struct { + baseAny + val int64 +} + +func (any *int64Any) LastError() error { + return nil +} + +func (any *int64Any) ValueType() ValueType { + return NumberValue +} + +func (any *int64Any) MustBeValid() Any { + return any +} + +func (any *int64Any) ToBool() bool { + return any.val != 0 +} + +func (any *int64Any) ToInt() int { + return int(any.val) +} + +func (any *int64Any) ToInt32() int32 { + return int32(any.val) +} + +func (any *int64Any) ToInt64() int64 { + return any.val +} + +func (any *int64Any) ToUint() uint { + return uint(any.val) +} + +func (any *int64Any) ToUint32() uint32 { + return uint32(any.val) +} + +func (any *int64Any) ToUint64() uint64 { + return uint64(any.val) +} + +func (any *int64Any) ToFloat32() float32 { + return float32(any.val) +} + +func (any *int64Any) ToFloat64() float64 { + return float64(any.val) +} + +func (any *int64Any) ToString() string { + return strconv.FormatInt(any.val, 10) +} + +func (any *int64Any) WriteTo(stream *Stream) { + stream.WriteInt64(any.val) +} + +func (any *int64Any) Parse() *Iterator { + return nil +} + +func (any *int64Any) GetInterface() interface{} { + return any.val +} diff --git a/vendor/github.com/json-iterator/go/any_invalid.go b/vendor/github.com/json-iterator/go/any_invalid.go new file mode 100644 index 0000000000000..1d859eac3274a --- /dev/null +++ b/vendor/github.com/json-iterator/go/any_invalid.go @@ -0,0 +1,82 @@ +package jsoniter + +import "fmt" + +type invalidAny struct { + baseAny + err error +} + +func newInvalidAny(path []interface{}) *invalidAny { + return &invalidAny{baseAny{}, fmt.Errorf("%v not found", path)} +} + +func (any *invalidAny) LastError() error { + return any.err +} + +func (any *invalidAny) ValueType() ValueType { + return InvalidValue +} + +func (any *invalidAny) MustBeValid() Any { + panic(any.err) +} + +func (any *invalidAny) ToBool() bool { + return false +} + +func (any *invalidAny) ToInt() int { + return 0 +} + +func (any *invalidAny) ToInt32() int32 { + return 0 +} + +func (any *invalidAny) ToInt64() int64 { + return 0 +} + +func (any *invalidAny) ToUint() uint { + return 0 +} + +func (any *invalidAny) ToUint32() uint32 { + return 0 +} + +func (any *invalidAny) ToUint64() uint64 { + return 0 +} + +func (any *invalidAny) ToFloat32() float32 { + return 0 +} + +func (any *invalidAny) ToFloat64() float64 { + return 0 +} + +func (any *invalidAny) ToString() string { + return "" +} + +func (any *invalidAny) WriteTo(stream *Stream) { +} + +func (any *invalidAny) Get(path ...interface{}) Any { + if any.err == nil { + return &invalidAny{baseAny{}, fmt.Errorf("get %v from invalid", path)} + } + return &invalidAny{baseAny{}, fmt.Errorf("%v, get %v from invalid", any.err, path)} +} + +func (any *invalidAny) Parse() *Iterator { + return nil +} + +func (any *invalidAny) GetInterface() interface{} { + return nil +} diff --git a/vendor/github.com/json-iterator/go/any_nil.go b/vendor/github.com/json-iterator/go/any_nil.go new file mode 100644 index 0000000000000..d04cb54c11c1e --- /dev/null +++ b/vendor/github.com/json-iterator/go/any_nil.go @@ -0,0 +1,69 @@ +package jsoniter + +type nilAny struct { + baseAny +} + +func (any *nilAny) LastError() error { + return nil +} + +func (any *nilAny) ValueType() ValueType { + return NilValue +} + +func (any *nilAny) MustBeValid() Any { + return any +} + +func (any *nilAny) ToBool() bool { + return false +} + +func (any *nilAny) ToInt() int { + return 0 +} + +func (any *nilAny) ToInt32() int32 { + return 0 +} + +func (any *nilAny) ToInt64() int64 { + return 0 +} + +func (any *nilAny) ToUint() uint { + return 0 +} + +func (any *nilAny) ToUint32() uint32 { + return 0 +} + +func (any *nilAny) ToUint64() uint64 { + return 0 +} + +func (any *nilAny) ToFloat32() float32 { + return 0 +} + +func (any *nilAny) ToFloat64() float64 { + return 0 +} + +func (any *nilAny) ToString() string { + return "" +} + +func (any *nilAny) WriteTo(stream *Stream) { + stream.WriteNil() +} + +func (any *nilAny) Parse() *Iterator { + return nil +} + +func (any *nilAny) GetInterface() interface{} { + return nil +} diff --git a/vendor/github.com/json-iterator/go/any_number.go b/vendor/github.com/json-iterator/go/any_number.go new file mode 100644 index 0000000000000..9d1e901a66ad3 --- /dev/null +++ b/vendor/github.com/json-iterator/go/any_number.go @@ -0,0 +1,123 @@ +package jsoniter + +import ( + "io" + "unsafe" +) + +type numberLazyAny struct { + baseAny + cfg *frozenConfig + buf []byte + err error +} + +func (any *numberLazyAny) ValueType() ValueType { + return NumberValue +} + +func (any *numberLazyAny) MustBeValid() Any { + return any +} + +func (any *numberLazyAny) LastError() error { + return any.err +} + +func (any *numberLazyAny) ToBool() bool { + return any.ToFloat64() != 0 +} + +func (any *numberLazyAny) ToInt() int { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + val := iter.ReadInt() + if iter.Error != nil && iter.Error != io.EOF { + any.err = iter.Error + } + return val +} + +func (any *numberLazyAny) ToInt32() int32 { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + val := iter.ReadInt32() + if iter.Error != nil && iter.Error != io.EOF { + any.err = iter.Error + } + return val +} + +func (any *numberLazyAny) ToInt64() int64 { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + val := iter.ReadInt64() + if iter.Error != nil && iter.Error != io.EOF { + any.err = iter.Error + } + return val +} + +func (any *numberLazyAny) ToUint() uint { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + val := iter.ReadUint() + if iter.Error != nil && iter.Error != io.EOF { + any.err = iter.Error + } + return val +} + +func (any *numberLazyAny) ToUint32() uint32 { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + val := iter.ReadUint32() + if iter.Error != nil && iter.Error != io.EOF { + any.err = iter.Error + } + return val +} + +func (any *numberLazyAny) ToUint64() uint64 { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + val := iter.ReadUint64() + if iter.Error != nil && iter.Error != io.EOF { + any.err = iter.Error + } + return val +} + +func (any *numberLazyAny) ToFloat32() float32 { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + val := iter.ReadFloat32() + if iter.Error != nil && iter.Error != io.EOF { + any.err = iter.Error + } + return val +} + +func (any *numberLazyAny) ToFloat64() float64 { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + val := iter.ReadFloat64() + if iter.Error != nil && iter.Error != io.EOF { + any.err = iter.Error + } + return val +} + +func (any *numberLazyAny) ToString() string { + return *(*string)(unsafe.Pointer(&any.buf)) +} + +func (any *numberLazyAny) WriteTo(stream *Stream) { + stream.Write(any.buf) +} + +func (any *numberLazyAny) GetInterface() interface{} { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + return iter.Read() +} diff --git a/vendor/github.com/json-iterator/go/any_object.go b/vendor/github.com/json-iterator/go/any_object.go new file mode 100644 index 0000000000000..c44ef5c989a46 --- /dev/null +++ b/vendor/github.com/json-iterator/go/any_object.go @@ -0,0 +1,374 @@ +package jsoniter + +import ( + "reflect" + "unsafe" +) + +type objectLazyAny struct { + baseAny + cfg *frozenConfig + buf []byte + err error +} + +func (any *objectLazyAny) ValueType() ValueType { + return ObjectValue +} + +func (any *objectLazyAny) MustBeValid() Any { + return any +} + +func (any *objectLazyAny) LastError() error { + return any.err +} + +func (any *objectLazyAny) ToBool() bool { + return true +} + +func (any *objectLazyAny) ToInt() int { + return 0 +} + +func (any *objectLazyAny) ToInt32() int32 { + return 0 +} + +func (any *objectLazyAny) ToInt64() int64 { + return 0 +} + +func (any *objectLazyAny) ToUint() uint { + return 0 +} + +func (any *objectLazyAny) ToUint32() uint32 { + return 0 +} + +func (any *objectLazyAny) ToUint64() uint64 { + return 0 +} + +func (any *objectLazyAny) ToFloat32() float32 { + return 0 +} + +func (any *objectLazyAny) ToFloat64() float64 { + return 0 +} + +func (any *objectLazyAny) ToString() string { + return *(*string)(unsafe.Pointer(&any.buf)) +} + +func (any *objectLazyAny) ToVal(obj interface{}) { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + iter.ReadVal(obj) +} + +func (any *objectLazyAny) Get(path ...interface{}) Any { + if len(path) == 0 { + return any + } + switch firstPath := path[0].(type) { + case string: + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + valueBytes := locateObjectField(iter, firstPath) + if valueBytes == nil { + return newInvalidAny(path) + } + iter.ResetBytes(valueBytes) + return locatePath(iter, path[1:]) + case int32: + if '*' == firstPath { + mappedAll := map[string]Any{} + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + iter.ReadMapCB(func(iter *Iterator, field string) bool { + mapped := locatePath(iter, path[1:]) + if mapped.ValueType() != InvalidValue { + mappedAll[field] = mapped + } + return true + }) + return wrapMap(mappedAll) + } + return newInvalidAny(path) + default: + return newInvalidAny(path) + } +} + +func (any *objectLazyAny) Keys() []string { + keys := []string{} + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + iter.ReadMapCB(func(iter *Iterator, field string) bool { + iter.Skip() + keys = append(keys, field) + return true + }) + return keys +} + +func (any *objectLazyAny) Size() int { + size := 0 + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + iter.ReadObjectCB(func(iter *Iterator, field string) bool { + iter.Skip() + size++ + return true + }) + return size +} + +func (any *objectLazyAny) WriteTo(stream *Stream) { + stream.Write(any.buf) +} + +func (any *objectLazyAny) GetInterface() interface{} { + iter := any.cfg.BorrowIterator(any.buf) + defer any.cfg.ReturnIterator(iter) + return iter.Read() +} + +type objectAny struct { + baseAny + err error + val reflect.Value +} + +func wrapStruct(val interface{}) *objectAny { + return &objectAny{baseAny{}, nil, reflect.ValueOf(val)} +} + +func (any *objectAny) ValueType() ValueType { + return ObjectValue +} + +func (any *objectAny) MustBeValid() Any { + return any +} + +func (any *objectAny) Parse() *Iterator { + return nil +} + +func (any *objectAny) LastError() error { + return any.err +} + +func (any *objectAny) ToBool() bool { + return any.val.NumField() != 0 +} + +func (any *objectAny) ToInt() int { + return 0 +} + +func (any *objectAny) ToInt32() int32 { + return 0 +} + +func (any *objectAny) ToInt64() int64 { + return 0 +} + +func (any *objectAny) ToUint() uint { + return 0 +} + +func (any *objectAny) ToUint32() uint32 { + return 0 +} + +func (any *objectAny) ToUint64() uint64 { + return 0 +} + +func (any *objectAny) ToFloat32() float32 { + return 0 +} + +func (any *objectAny) ToFloat64() float64 { + return 0 +} + +func (any *objectAny) ToString() string { + str, err := MarshalToString(any.val.Interface()) + any.err = err + return str +} + +func (any *objectAny) Get(path ...interface{}) Any { + if len(path) == 0 { + return any + } + switch firstPath := path[0].(type) { + case string: + field := any.val.FieldByName(firstPath) + if !field.IsValid() { + return newInvalidAny(path) + } + return Wrap(field.Interface()) + case int32: + if '*' == firstPath { + mappedAll := map[string]Any{} + for i := 0; i < any.val.NumField(); i++ { + field := any.val.Field(i) + if field.CanInterface() { + mapped := Wrap(field.Interface()).Get(path[1:]...) + if mapped.ValueType() != InvalidValue { + mappedAll[any.val.Type().Field(i).Name] = mapped + } + } + } + return wrapMap(mappedAll) + } + return newInvalidAny(path) + default: + return newInvalidAny(path) + } +} + +func (any *objectAny) Keys() []string { + keys := make([]string, 0, any.val.NumField()) + for i := 0; i < any.val.NumField(); i++ { + keys = append(keys, any.val.Type().Field(i).Name) + } + return keys +} + +func (any *objectAny) Size() int { + return any.val.NumField() +} + +func (any *objectAny) WriteTo(stream *Stream) { + stream.WriteVal(any.val) +} + +func (any *objectAny) GetInterface() interface{} { + return any.val.Interface() +} + +type mapAny struct { + baseAny + err error + val reflect.Value +} + +func wrapMap(val interface{}) *mapAny { + return &mapAny{baseAny{}, nil, reflect.ValueOf(val)} +} + +func (any *mapAny) ValueType() ValueType { + return ObjectValue +} + +func (any *mapAny) MustBeValid() Any { + return any +} + +func (any *mapAny) Parse() *Iterator { + return nil +} + +func (any *mapAny) LastError() error { + return any.err +} + +func (any *mapAny) ToBool() bool { + return true +} + +func (any *mapAny) ToInt() int { + return 0 +} + +func (any *mapAny) ToInt32() int32 { + return 0 +} + +func (any *mapAny) ToInt64() int64 { + return 0 +} + +func (any *mapAny) ToUint() uint { + return 0 +} + +func (any *mapAny) ToUint32() uint32 { + return 0 +} + +func (any *mapAny) ToUint64() uint64 { + return 0 +} + +func (any *mapAny) ToFloat32() float32 { + return 0 +} + +func (any *mapAny) ToFloat64() float64 { + return 0 +} + +func (any *mapAny) ToString() string { + str, err := MarshalToString(any.val.Interface()) + any.err = err + return str +} + +func (any *mapAny) Get(path ...interface{}) Any { + if len(path) == 0 { + return any + } + switch firstPath := path[0].(type) { + case int32: + if '*' == firstPath { + mappedAll := map[string]Any{} + for _, key := range any.val.MapKeys() { + keyAsStr := key.String() + element := Wrap(any.val.MapIndex(key).Interface()) + mapped := element.Get(path[1:]...) + if mapped.ValueType() != InvalidValue { + mappedAll[keyAsStr] = mapped + } + } + return wrapMap(mappedAll) + } + return newInvalidAny(path) + default: + value := any.val.MapIndex(reflect.ValueOf(firstPath)) + if !value.IsValid() { + return newInvalidAny(path) + } + return Wrap(value.Interface()) + } +} + +func (any *mapAny) Keys() []string { + keys := make([]string, 0, any.val.Len()) + for _, key := range any.val.MapKeys() { + keys = append(keys, key.String()) + } + return keys +} + +func (any *mapAny) Size() int { + return any.val.Len() +} + +func (any *mapAny) WriteTo(stream *Stream) { + stream.WriteVal(any.val) +} + +func (any *mapAny) GetInterface() interface{} { + return any.val.Interface() +} diff --git a/vendor/github.com/json-iterator/go/any_str.go b/vendor/github.com/json-iterator/go/any_str.go new file mode 100644 index 0000000000000..a4b93c78c8221 --- /dev/null +++ b/vendor/github.com/json-iterator/go/any_str.go @@ -0,0 +1,166 @@ +package jsoniter + +import ( + "fmt" + "strconv" +) + +type stringAny struct { + baseAny + val string +} + +func (any *stringAny) Get(path ...interface{}) Any { + if len(path) == 0 { + return any + } + return &invalidAny{baseAny{}, fmt.Errorf("GetIndex %v from simple value", path)} +} + +func (any *stringAny) Parse() *Iterator { + return nil +} + +func (any *stringAny) ValueType() ValueType { + return StringValue +} + +func (any *stringAny) MustBeValid() Any { + return any +} + +func (any *stringAny) LastError() error { + return nil +} + +func (any *stringAny) ToBool() bool { + str := any.ToString() + if str == "0" { + return false + } + for _, c := range str { + switch c { + case ' ', '\n', '\r', '\t': + default: + return true + } + } + return false +} + +func (any *stringAny) ToInt() int { + return int(any.ToInt64()) + +} + +func (any *stringAny) ToInt32() int32 { + return int32(any.ToInt64()) +} + +func (any *stringAny) ToInt64() int64 { + if any.val == "" { + return 0 + } + + flag := 1 + startPos := 0 + endPos := 0 + if any.val[0] == '+' || any.val[0] == '-' { + startPos = 1 + } + + if any.val[0] == '-' { + flag = -1 + } + + for i := startPos; i < len(any.val); i++ { + if any.val[i] >= '0' && any.val[i] <= '9' { + endPos = i + 1 + } else { + break + } + } + parsed, _ := strconv.ParseInt(any.val[startPos:endPos], 10, 64) + return int64(flag) * parsed +} + +func (any *stringAny) ToUint() uint { + return uint(any.ToUint64()) +} + +func (any *stringAny) ToUint32() uint32 { + return uint32(any.ToUint64()) +} + +func (any *stringAny) ToUint64() uint64 { + if any.val == "" { + return 0 + } + + startPos := 0 + endPos := 0 + + if any.val[0] == '-' { + return 0 + } + if any.val[0] == '+' { + startPos = 1 + } + + for i := startPos; i < len(any.val); i++ { + if any.val[i] >= '0' && any.val[i] <= '9' { + endPos = i + 1 + } else { + break + } + } + parsed, _ := strconv.ParseUint(any.val[startPos:endPos], 10, 64) + return parsed +} + +func (any *stringAny) ToFloat32() float32 { + return float32(any.ToFloat64()) +} + +func (any *stringAny) ToFloat64() float64 { + if len(any.val) == 0 { + return 0 + } + + // first char invalid + if any.val[0] != '+' && any.val[0] != '-' && (any.val[0] > '9' || any.val[0] < '0') { + return 0 + } + + // extract valid num expression from string + // eg 123true => 123, -12.12xxa => -12.12 + endPos := 1 + for i := 1; i < len(any.val); i++ { + if any.val[i] == '.' || any.val[i] == 'e' || any.val[i] == 'E' || any.val[i] == '+' || any.val[i] == '-' { + endPos = i + 1 + continue + } + + // end position is the first char which is not digit + if any.val[i] >= '0' && any.val[i] <= '9' { + endPos = i + 1 + } else { + endPos = i + break + } + } + parsed, _ := strconv.ParseFloat(any.val[:endPos], 64) + return parsed +} + +func (any *stringAny) ToString() string { + return any.val +} + +func (any *stringAny) WriteTo(stream *Stream) { + stream.WriteString(any.val) +} + +func (any *stringAny) GetInterface() interface{} { + return any.val +} diff --git a/vendor/github.com/json-iterator/go/any_uint32.go b/vendor/github.com/json-iterator/go/any_uint32.go new file mode 100644 index 0000000000000..656bbd33d7ee9 --- /dev/null +++ b/vendor/github.com/json-iterator/go/any_uint32.go @@ -0,0 +1,74 @@ +package jsoniter + +import ( + "strconv" +) + +type uint32Any struct { + baseAny + val uint32 +} + +func (any *uint32Any) LastError() error { + return nil +} + +func (any *uint32Any) ValueType() ValueType { + return NumberValue +} + +func (any *uint32Any) MustBeValid() Any { + return any +} + +func (any *uint32Any) ToBool() bool { + return any.val != 0 +} + +func (any *uint32Any) ToInt() int { + return int(any.val) +} + +func (any *uint32Any) ToInt32() int32 { + return int32(any.val) +} + +func (any *uint32Any) ToInt64() int64 { + return int64(any.val) +} + +func (any *uint32Any) ToUint() uint { + return uint(any.val) +} + +func (any *uint32Any) ToUint32() uint32 { + return any.val +} + +func (any *uint32Any) ToUint64() uint64 { + return uint64(any.val) +} + +func (any *uint32Any) ToFloat32() float32 { + return float32(any.val) +} + +func (any *uint32Any) ToFloat64() float64 { + return float64(any.val) +} + +func (any *uint32Any) ToString() string { + return strconv.FormatInt(int64(any.val), 10) +} + +func (any *uint32Any) WriteTo(stream *Stream) { + stream.WriteUint32(any.val) +} + +func (any *uint32Any) Parse() *Iterator { + return nil +} + +func (any *uint32Any) GetInterface() interface{} { + return any.val +} diff --git a/vendor/github.com/json-iterator/go/any_uint64.go b/vendor/github.com/json-iterator/go/any_uint64.go new file mode 100644 index 0000000000000..7df2fce33ba97 --- /dev/null +++ b/vendor/github.com/json-iterator/go/any_uint64.go @@ -0,0 +1,74 @@ +package jsoniter + +import ( + "strconv" +) + +type uint64Any struct { + baseAny + val uint64 +} + +func (any *uint64Any) LastError() error { + return nil +} + +func (any *uint64Any) ValueType() ValueType { + return NumberValue +} + +func (any *uint64Any) MustBeValid() Any { + return any +} + +func (any *uint64Any) ToBool() bool { + return any.val != 0 +} + +func (any *uint64Any) ToInt() int { + return int(any.val) +} + +func (any *uint64Any) ToInt32() int32 { + return int32(any.val) +} + +func (any *uint64Any) ToInt64() int64 { + return int64(any.val) +} + +func (any *uint64Any) ToUint() uint { + return uint(any.val) +} + +func (any *uint64Any) ToUint32() uint32 { + return uint32(any.val) +} + +func (any *uint64Any) ToUint64() uint64 { + return any.val +} + +func (any *uint64Any) ToFloat32() float32 { + return float32(any.val) +} + +func (any *uint64Any) ToFloat64() float64 { + return float64(any.val) +} + +func (any *uint64Any) ToString() string { + return strconv.FormatUint(any.val, 10) +} + +func (any *uint64Any) WriteTo(stream *Stream) { + stream.WriteUint64(any.val) +} + +func (any *uint64Any) Parse() *Iterator { + return nil +} + +func (any *uint64Any) GetInterface() interface{} { + return any.val +} diff --git a/vendor/github.com/json-iterator/go/build.sh b/vendor/github.com/json-iterator/go/build.sh new file mode 100644 index 0000000000000..b45ef688313ec --- /dev/null +++ b/vendor/github.com/json-iterator/go/build.sh @@ -0,0 +1,12 @@ +#!/bin/bash +set -e +set -x + +if [ ! -d /tmp/build-golang/src/github.com/json-iterator ]; then + mkdir -p /tmp/build-golang/src/github.com/json-iterator + ln -s $PWD /tmp/build-golang/src/github.com/json-iterator/go +fi +export GOPATH=/tmp/build-golang +go get -u github.com/golang/dep/cmd/dep +cd /tmp/build-golang/src/github.com/json-iterator/go +exec $GOPATH/bin/dep ensure -update diff --git a/vendor/github.com/json-iterator/go/config.go b/vendor/github.com/json-iterator/go/config.go new file mode 100644 index 0000000000000..8c58fcba5922f --- /dev/null +++ b/vendor/github.com/json-iterator/go/config.go @@ -0,0 +1,375 @@ +package jsoniter + +import ( + "encoding/json" + "io" + "reflect" + "sync" + "unsafe" + + "github.com/modern-go/concurrent" + "github.com/modern-go/reflect2" +) + +// Config customize how the API should behave. +// The API is created from Config by Froze. +type Config struct { + IndentionStep int + MarshalFloatWith6Digits bool + EscapeHTML bool + SortMapKeys bool + UseNumber bool + DisallowUnknownFields bool + TagKey string + OnlyTaggedField bool + ValidateJsonRawMessage bool + ObjectFieldMustBeSimpleString bool + CaseSensitive bool +} + +// API the public interface of this package. +// Primary Marshal and Unmarshal. +type API interface { + IteratorPool + StreamPool + MarshalToString(v interface{}) (string, error) + Marshal(v interface{}) ([]byte, error) + MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) + UnmarshalFromString(str string, v interface{}) error + Unmarshal(data []byte, v interface{}) error + Get(data []byte, path ...interface{}) Any + NewEncoder(writer io.Writer) *Encoder + NewDecoder(reader io.Reader) *Decoder + Valid(data []byte) bool + RegisterExtension(extension Extension) + DecoderOf(typ reflect2.Type) ValDecoder + EncoderOf(typ reflect2.Type) ValEncoder +} + +// ConfigDefault the default API +var ConfigDefault = Config{ + EscapeHTML: true, +}.Froze() + +// ConfigCompatibleWithStandardLibrary tries to be 100% compatible with standard library behavior +var ConfigCompatibleWithStandardLibrary = Config{ + EscapeHTML: true, + SortMapKeys: true, + ValidateJsonRawMessage: true, +}.Froze() + +// ConfigFastest marshals float with only 6 digits precision +var ConfigFastest = Config{ + EscapeHTML: false, + MarshalFloatWith6Digits: true, // will lose precession + ObjectFieldMustBeSimpleString: true, // do not unescape object field +}.Froze() + +type frozenConfig struct { + configBeforeFrozen Config + sortMapKeys bool + indentionStep int + objectFieldMustBeSimpleString bool + onlyTaggedField bool + disallowUnknownFields bool + decoderCache *concurrent.Map + encoderCache *concurrent.Map + encoderExtension Extension + decoderExtension Extension + extraExtensions []Extension + streamPool *sync.Pool + iteratorPool *sync.Pool + caseSensitive bool +} + +func (cfg *frozenConfig) initCache() { + cfg.decoderCache = concurrent.NewMap() + cfg.encoderCache = concurrent.NewMap() +} + +func (cfg *frozenConfig) addDecoderToCache(cacheKey uintptr, decoder ValDecoder) { + cfg.decoderCache.Store(cacheKey, decoder) +} + +func (cfg *frozenConfig) addEncoderToCache(cacheKey uintptr, encoder ValEncoder) { + cfg.encoderCache.Store(cacheKey, encoder) +} + +func (cfg *frozenConfig) getDecoderFromCache(cacheKey uintptr) ValDecoder { + decoder, found := cfg.decoderCache.Load(cacheKey) + if found { + return decoder.(ValDecoder) + } + return nil +} + +func (cfg *frozenConfig) getEncoderFromCache(cacheKey uintptr) ValEncoder { + encoder, found := cfg.encoderCache.Load(cacheKey) + if found { + return encoder.(ValEncoder) + } + return nil +} + +var cfgCache = concurrent.NewMap() + +func getFrozenConfigFromCache(cfg Config) *frozenConfig { + obj, found := cfgCache.Load(cfg) + if found { + return obj.(*frozenConfig) + } + return nil +} + +func addFrozenConfigToCache(cfg Config, frozenConfig *frozenConfig) { + cfgCache.Store(cfg, frozenConfig) +} + +// Froze forge API from config +func (cfg Config) Froze() API { + api := &frozenConfig{ + sortMapKeys: cfg.SortMapKeys, + indentionStep: cfg.IndentionStep, + objectFieldMustBeSimpleString: cfg.ObjectFieldMustBeSimpleString, + onlyTaggedField: cfg.OnlyTaggedField, + disallowUnknownFields: cfg.DisallowUnknownFields, + caseSensitive: cfg.CaseSensitive, + } + api.streamPool = &sync.Pool{ + New: func() interface{} { + return NewStream(api, nil, 512) + }, + } + api.iteratorPool = &sync.Pool{ + New: func() interface{} { + return NewIterator(api) + }, + } + api.initCache() + encoderExtension := EncoderExtension{} + decoderExtension := DecoderExtension{} + if cfg.MarshalFloatWith6Digits { + api.marshalFloatWith6Digits(encoderExtension) + } + if cfg.EscapeHTML { + api.escapeHTML(encoderExtension) + } + if cfg.UseNumber { + api.useNumber(decoderExtension) + } + if cfg.ValidateJsonRawMessage { + api.validateJsonRawMessage(encoderExtension) + } + api.encoderExtension = encoderExtension + api.decoderExtension = decoderExtension + api.configBeforeFrozen = cfg + return api +} + +func (cfg Config) frozeWithCacheReuse(extraExtensions []Extension) *frozenConfig { + api := getFrozenConfigFromCache(cfg) + if api != nil { + return api + } + api = cfg.Froze().(*frozenConfig) + for _, extension := range extraExtensions { + api.RegisterExtension(extension) + } + addFrozenConfigToCache(cfg, api) + return api +} + +func (cfg *frozenConfig) validateJsonRawMessage(extension EncoderExtension) { + encoder := &funcEncoder{func(ptr unsafe.Pointer, stream *Stream) { + rawMessage := *(*json.RawMessage)(ptr) + iter := cfg.BorrowIterator([]byte(rawMessage)) + iter.Read() + if iter.Error != nil { + stream.WriteRaw("null") + } else { + cfg.ReturnIterator(iter) + stream.WriteRaw(string(rawMessage)) + } + }, func(ptr unsafe.Pointer) bool { + return len(*((*json.RawMessage)(ptr))) == 0 + }} + extension[reflect2.TypeOfPtr((*json.RawMessage)(nil)).Elem()] = encoder + extension[reflect2.TypeOfPtr((*RawMessage)(nil)).Elem()] = encoder +} + +func (cfg *frozenConfig) useNumber(extension DecoderExtension) { + extension[reflect2.TypeOfPtr((*interface{})(nil)).Elem()] = &funcDecoder{func(ptr unsafe.Pointer, iter *Iterator) { + exitingValue := *((*interface{})(ptr)) + if exitingValue != nil && reflect.TypeOf(exitingValue).Kind() == reflect.Ptr { + iter.ReadVal(exitingValue) + return + } + if iter.WhatIsNext() == NumberValue { + *((*interface{})(ptr)) = json.Number(iter.readNumberAsString()) + } else { + *((*interface{})(ptr)) = iter.Read() + } + }} +} +func (cfg *frozenConfig) getTagKey() string { + tagKey := cfg.configBeforeFrozen.TagKey + if tagKey == "" { + return "json" + } + return tagKey +} + +func (cfg *frozenConfig) RegisterExtension(extension Extension) { + cfg.extraExtensions = append(cfg.extraExtensions, extension) + copied := cfg.configBeforeFrozen + cfg.configBeforeFrozen = copied +} + +type lossyFloat32Encoder struct { +} + +func (encoder *lossyFloat32Encoder) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteFloat32Lossy(*((*float32)(ptr))) +} + +func (encoder *lossyFloat32Encoder) IsEmpty(ptr unsafe.Pointer) bool { + return *((*float32)(ptr)) == 0 +} + +type lossyFloat64Encoder struct { +} + +func (encoder *lossyFloat64Encoder) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteFloat64Lossy(*((*float64)(ptr))) +} + +func (encoder *lossyFloat64Encoder) IsEmpty(ptr unsafe.Pointer) bool { + return *((*float64)(ptr)) == 0 +} + +// EnableLossyFloatMarshalling keeps 10**(-6) precision +// for float variables for better performance. +func (cfg *frozenConfig) marshalFloatWith6Digits(extension EncoderExtension) { + // for better performance + extension[reflect2.TypeOfPtr((*float32)(nil)).Elem()] = &lossyFloat32Encoder{} + extension[reflect2.TypeOfPtr((*float64)(nil)).Elem()] = &lossyFloat64Encoder{} +} + +type htmlEscapedStringEncoder struct { +} + +func (encoder *htmlEscapedStringEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + str := *((*string)(ptr)) + stream.WriteStringWithHTMLEscaped(str) +} + +func (encoder *htmlEscapedStringEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return *((*string)(ptr)) == "" +} + +func (cfg *frozenConfig) escapeHTML(encoderExtension EncoderExtension) { + encoderExtension[reflect2.TypeOfPtr((*string)(nil)).Elem()] = &htmlEscapedStringEncoder{} +} + +func (cfg *frozenConfig) cleanDecoders() { + typeDecoders = map[string]ValDecoder{} + fieldDecoders = map[string]ValDecoder{} + *cfg = *(cfg.configBeforeFrozen.Froze().(*frozenConfig)) +} + +func (cfg *frozenConfig) cleanEncoders() { + typeEncoders = map[string]ValEncoder{} + fieldEncoders = map[string]ValEncoder{} + *cfg = *(cfg.configBeforeFrozen.Froze().(*frozenConfig)) +} + +func (cfg *frozenConfig) MarshalToString(v interface{}) (string, error) { + stream := cfg.BorrowStream(nil) + defer cfg.ReturnStream(stream) + stream.WriteVal(v) + if stream.Error != nil { + return "", stream.Error + } + return string(stream.Buffer()), nil +} + +func (cfg *frozenConfig) Marshal(v interface{}) ([]byte, error) { + stream := cfg.BorrowStream(nil) + defer cfg.ReturnStream(stream) + stream.WriteVal(v) + if stream.Error != nil { + return nil, stream.Error + } + result := stream.Buffer() + copied := make([]byte, len(result)) + copy(copied, result) + return copied, nil +} + +func (cfg *frozenConfig) MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) { + if prefix != "" { + panic("prefix is not supported") + } + for _, r := range indent { + if r != ' ' { + panic("indent can only be space") + } + } + newCfg := cfg.configBeforeFrozen + newCfg.IndentionStep = len(indent) + return newCfg.frozeWithCacheReuse(cfg.extraExtensions).Marshal(v) +} + +func (cfg *frozenConfig) UnmarshalFromString(str string, v interface{}) error { + data := []byte(str) + iter := cfg.BorrowIterator(data) + defer cfg.ReturnIterator(iter) + iter.ReadVal(v) + c := iter.nextToken() + if c == 0 { + if iter.Error == io.EOF { + return nil + } + return iter.Error + } + iter.ReportError("Unmarshal", "there are bytes left after unmarshal") + return iter.Error +} + +func (cfg *frozenConfig) Get(data []byte, path ...interface{}) Any { + iter := cfg.BorrowIterator(data) + defer cfg.ReturnIterator(iter) + return locatePath(iter, path) +} + +func (cfg *frozenConfig) Unmarshal(data []byte, v interface{}) error { + iter := cfg.BorrowIterator(data) + defer cfg.ReturnIterator(iter) + iter.ReadVal(v) + c := iter.nextToken() + if c == 0 { + if iter.Error == io.EOF { + return nil + } + return iter.Error + } + iter.ReportError("Unmarshal", "there are bytes left after unmarshal") + return iter.Error +} + +func (cfg *frozenConfig) NewEncoder(writer io.Writer) *Encoder { + stream := NewStream(cfg, writer, 512) + return &Encoder{stream} +} + +func (cfg *frozenConfig) NewDecoder(reader io.Reader) *Decoder { + iter := Parse(cfg, reader, 512) + return &Decoder{iter} +} + +func (cfg *frozenConfig) Valid(data []byte) bool { + iter := cfg.BorrowIterator(data) + defer cfg.ReturnIterator(iter) + iter.Skip() + return iter.Error == nil +} diff --git a/vendor/github.com/json-iterator/go/fuzzy_mode_convert_table.md b/vendor/github.com/json-iterator/go/fuzzy_mode_convert_table.md new file mode 100644 index 0000000000000..3095662b06100 --- /dev/null +++ b/vendor/github.com/json-iterator/go/fuzzy_mode_convert_table.md @@ -0,0 +1,7 @@ +| json type \ dest type | bool | int | uint | float |string| +| --- | --- | --- | --- |--|--| +| number | positive => true
negative => true
zero => false| 23.2 => 23
-32.1 => -32| 12.1 => 12
-12.1 => 0|as normal|same as origin| +| string | empty string => false
string "0" => false
other strings => true | "123.32" => 123
"-123.4" => -123
"123.23xxxw" => 123
"abcde12" => 0
"-32.1" => -32| 13.2 => 13
-1.1 => 0 |12.1 => 12.1
-12.3 => -12.3
12.4xxa => 12.4
+1.1e2 =>110 |same as origin| +| bool | true => true
false => false| true => 1
false => 0 | true => 1
false => 0 |true => 1
false => 0|true => "true"
false => "false"| +| object | true | 0 | 0 |0|originnal json| +| array | empty array => false
nonempty array => true| [] => 0
[1,2] => 1 | [] => 0
[1,2] => 1 |[] => 0
[1,2] => 1|original json| \ No newline at end of file diff --git a/vendor/github.com/json-iterator/go/go.mod b/vendor/github.com/json-iterator/go/go.mod new file mode 100644 index 0000000000000..e05c42ff58b81 --- /dev/null +++ b/vendor/github.com/json-iterator/go/go.mod @@ -0,0 +1,11 @@ +module github.com/json-iterator/go + +go 1.12 + +require ( + github.com/davecgh/go-spew v1.1.1 + github.com/google/gofuzz v1.0.0 + github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 + github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 + github.com/stretchr/testify v1.3.0 +) diff --git a/vendor/github.com/json-iterator/go/go.sum b/vendor/github.com/json-iterator/go/go.sum new file mode 100644 index 0000000000000..d778b5a14d633 --- /dev/null +++ b/vendor/github.com/json-iterator/go/go.sum @@ -0,0 +1,14 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= diff --git a/vendor/github.com/json-iterator/go/iter.go b/vendor/github.com/json-iterator/go/iter.go new file mode 100644 index 0000000000000..29b31cf789506 --- /dev/null +++ b/vendor/github.com/json-iterator/go/iter.go @@ -0,0 +1,349 @@ +package jsoniter + +import ( + "encoding/json" + "fmt" + "io" +) + +// ValueType the type for JSON element +type ValueType int + +const ( + // InvalidValue invalid JSON element + InvalidValue ValueType = iota + // StringValue JSON element "string" + StringValue + // NumberValue JSON element 100 or 0.10 + NumberValue + // NilValue JSON element null + NilValue + // BoolValue JSON element true or false + BoolValue + // ArrayValue JSON element [] + ArrayValue + // ObjectValue JSON element {} + ObjectValue +) + +var hexDigits []byte +var valueTypes []ValueType + +func init() { + hexDigits = make([]byte, 256) + for i := 0; i < len(hexDigits); i++ { + hexDigits[i] = 255 + } + for i := '0'; i <= '9'; i++ { + hexDigits[i] = byte(i - '0') + } + for i := 'a'; i <= 'f'; i++ { + hexDigits[i] = byte((i - 'a') + 10) + } + for i := 'A'; i <= 'F'; i++ { + hexDigits[i] = byte((i - 'A') + 10) + } + valueTypes = make([]ValueType, 256) + for i := 0; i < len(valueTypes); i++ { + valueTypes[i] = InvalidValue + } + valueTypes['"'] = StringValue + valueTypes['-'] = NumberValue + valueTypes['0'] = NumberValue + valueTypes['1'] = NumberValue + valueTypes['2'] = NumberValue + valueTypes['3'] = NumberValue + valueTypes['4'] = NumberValue + valueTypes['5'] = NumberValue + valueTypes['6'] = NumberValue + valueTypes['7'] = NumberValue + valueTypes['8'] = NumberValue + valueTypes['9'] = NumberValue + valueTypes['t'] = BoolValue + valueTypes['f'] = BoolValue + valueTypes['n'] = NilValue + valueTypes['['] = ArrayValue + valueTypes['{'] = ObjectValue +} + +// Iterator is a io.Reader like object, with JSON specific read functions. +// Error is not returned as return value, but stored as Error member on this iterator instance. +type Iterator struct { + cfg *frozenConfig + reader io.Reader + buf []byte + head int + tail int + depth int + captureStartedAt int + captured []byte + Error error + Attachment interface{} // open for customized decoder +} + +// NewIterator creates an empty Iterator instance +func NewIterator(cfg API) *Iterator { + return &Iterator{ + cfg: cfg.(*frozenConfig), + reader: nil, + buf: nil, + head: 0, + tail: 0, + depth: 0, + } +} + +// Parse creates an Iterator instance from io.Reader +func Parse(cfg API, reader io.Reader, bufSize int) *Iterator { + return &Iterator{ + cfg: cfg.(*frozenConfig), + reader: reader, + buf: make([]byte, bufSize), + head: 0, + tail: 0, + depth: 0, + } +} + +// ParseBytes creates an Iterator instance from byte array +func ParseBytes(cfg API, input []byte) *Iterator { + return &Iterator{ + cfg: cfg.(*frozenConfig), + reader: nil, + buf: input, + head: 0, + tail: len(input), + depth: 0, + } +} + +// ParseString creates an Iterator instance from string +func ParseString(cfg API, input string) *Iterator { + return ParseBytes(cfg, []byte(input)) +} + +// Pool returns a pool can provide more iterator with same configuration +func (iter *Iterator) Pool() IteratorPool { + return iter.cfg +} + +// Reset reuse iterator instance by specifying another reader +func (iter *Iterator) Reset(reader io.Reader) *Iterator { + iter.reader = reader + iter.head = 0 + iter.tail = 0 + iter.depth = 0 + return iter +} + +// ResetBytes reuse iterator instance by specifying another byte array as input +func (iter *Iterator) ResetBytes(input []byte) *Iterator { + iter.reader = nil + iter.buf = input + iter.head = 0 + iter.tail = len(input) + iter.depth = 0 + return iter +} + +// WhatIsNext gets ValueType of relatively next json element +func (iter *Iterator) WhatIsNext() ValueType { + valueType := valueTypes[iter.nextToken()] + iter.unreadByte() + return valueType +} + +func (iter *Iterator) skipWhitespacesWithoutLoadMore() bool { + for i := iter.head; i < iter.tail; i++ { + c := iter.buf[i] + switch c { + case ' ', '\n', '\t', '\r': + continue + } + iter.head = i + return false + } + return true +} + +func (iter *Iterator) isObjectEnd() bool { + c := iter.nextToken() + if c == ',' { + return false + } + if c == '}' { + return true + } + iter.ReportError("isObjectEnd", "object ended prematurely, unexpected char "+string([]byte{c})) + return true +} + +func (iter *Iterator) nextToken() byte { + // a variation of skip whitespaces, returning the next non-whitespace token + for { + for i := iter.head; i < iter.tail; i++ { + c := iter.buf[i] + switch c { + case ' ', '\n', '\t', '\r': + continue + } + iter.head = i + 1 + return c + } + if !iter.loadMore() { + return 0 + } + } +} + +// ReportError record a error in iterator instance with current position. +func (iter *Iterator) ReportError(operation string, msg string) { + if iter.Error != nil { + if iter.Error != io.EOF { + return + } + } + peekStart := iter.head - 10 + if peekStart < 0 { + peekStart = 0 + } + peekEnd := iter.head + 10 + if peekEnd > iter.tail { + peekEnd = iter.tail + } + parsing := string(iter.buf[peekStart:peekEnd]) + contextStart := iter.head - 50 + if contextStart < 0 { + contextStart = 0 + } + contextEnd := iter.head + 50 + if contextEnd > iter.tail { + contextEnd = iter.tail + } + context := string(iter.buf[contextStart:contextEnd]) + iter.Error = fmt.Errorf("%s: %s, error found in #%v byte of ...|%s|..., bigger context ...|%s|...", + operation, msg, iter.head-peekStart, parsing, context) +} + +// CurrentBuffer gets current buffer as string for debugging purpose +func (iter *Iterator) CurrentBuffer() string { + peekStart := iter.head - 10 + if peekStart < 0 { + peekStart = 0 + } + return fmt.Sprintf("parsing #%v byte, around ...|%s|..., whole buffer ...|%s|...", iter.head, + string(iter.buf[peekStart:iter.head]), string(iter.buf[0:iter.tail])) +} + +func (iter *Iterator) readByte() (ret byte) { + if iter.head == iter.tail { + if iter.loadMore() { + ret = iter.buf[iter.head] + iter.head++ + return ret + } + return 0 + } + ret = iter.buf[iter.head] + iter.head++ + return ret +} + +func (iter *Iterator) loadMore() bool { + if iter.reader == nil { + if iter.Error == nil { + iter.head = iter.tail + iter.Error = io.EOF + } + return false + } + if iter.captured != nil { + iter.captured = append(iter.captured, + iter.buf[iter.captureStartedAt:iter.tail]...) + iter.captureStartedAt = 0 + } + for { + n, err := iter.reader.Read(iter.buf) + if n == 0 { + if err != nil { + if iter.Error == nil { + iter.Error = err + } + return false + } + } else { + iter.head = 0 + iter.tail = n + return true + } + } +} + +func (iter *Iterator) unreadByte() { + if iter.Error != nil { + return + } + iter.head-- + return +} + +// Read read the next JSON element as generic interface{}. +func (iter *Iterator) Read() interface{} { + valueType := iter.WhatIsNext() + switch valueType { + case StringValue: + return iter.ReadString() + case NumberValue: + if iter.cfg.configBeforeFrozen.UseNumber { + return json.Number(iter.readNumberAsString()) + } + return iter.ReadFloat64() + case NilValue: + iter.skipFourBytes('n', 'u', 'l', 'l') + return nil + case BoolValue: + return iter.ReadBool() + case ArrayValue: + arr := []interface{}{} + iter.ReadArrayCB(func(iter *Iterator) bool { + var elem interface{} + iter.ReadVal(&elem) + arr = append(arr, elem) + return true + }) + return arr + case ObjectValue: + obj := map[string]interface{}{} + iter.ReadMapCB(func(Iter *Iterator, field string) bool { + var elem interface{} + iter.ReadVal(&elem) + obj[field] = elem + return true + }) + return obj + default: + iter.ReportError("Read", fmt.Sprintf("unexpected value type: %v", valueType)) + return nil + } +} + +// limit maximum depth of nesting, as allowed by https://tools.ietf.org/html/rfc7159#section-9 +const maxDepth = 10000 + +func (iter *Iterator) incrementDepth() (success bool) { + iter.depth++ + if iter.depth <= maxDepth { + return true + } + iter.ReportError("incrementDepth", "exceeded max depth") + return false +} + +func (iter *Iterator) decrementDepth() (success bool) { + iter.depth-- + if iter.depth >= 0 { + return true + } + iter.ReportError("decrementDepth", "unexpected negative nesting") + return false +} diff --git a/vendor/github.com/json-iterator/go/iter_array.go b/vendor/github.com/json-iterator/go/iter_array.go new file mode 100644 index 0000000000000..204fe0e0922aa --- /dev/null +++ b/vendor/github.com/json-iterator/go/iter_array.go @@ -0,0 +1,64 @@ +package jsoniter + +// ReadArray read array element, tells if the array has more element to read. +func (iter *Iterator) ReadArray() (ret bool) { + c := iter.nextToken() + switch c { + case 'n': + iter.skipThreeBytes('u', 'l', 'l') + return false // null + case '[': + c = iter.nextToken() + if c != ']' { + iter.unreadByte() + return true + } + return false + case ']': + return false + case ',': + return true + default: + iter.ReportError("ReadArray", "expect [ or , or ] or n, but found "+string([]byte{c})) + return + } +} + +// ReadArrayCB read array with callback +func (iter *Iterator) ReadArrayCB(callback func(*Iterator) bool) (ret bool) { + c := iter.nextToken() + if c == '[' { + if !iter.incrementDepth() { + return false + } + c = iter.nextToken() + if c != ']' { + iter.unreadByte() + if !callback(iter) { + iter.decrementDepth() + return false + } + c = iter.nextToken() + for c == ',' { + if !callback(iter) { + iter.decrementDepth() + return false + } + c = iter.nextToken() + } + if c != ']' { + iter.ReportError("ReadArrayCB", "expect ] in the end, but found "+string([]byte{c})) + iter.decrementDepth() + return false + } + return iter.decrementDepth() + } + return iter.decrementDepth() + } + if c == 'n' { + iter.skipThreeBytes('u', 'l', 'l') + return true // null + } + iter.ReportError("ReadArrayCB", "expect [ or n, but found "+string([]byte{c})) + return false +} diff --git a/vendor/github.com/json-iterator/go/iter_float.go b/vendor/github.com/json-iterator/go/iter_float.go new file mode 100644 index 0000000000000..b9754638e8886 --- /dev/null +++ b/vendor/github.com/json-iterator/go/iter_float.go @@ -0,0 +1,339 @@ +package jsoniter + +import ( + "encoding/json" + "io" + "math/big" + "strconv" + "strings" + "unsafe" +) + +var floatDigits []int8 + +const invalidCharForNumber = int8(-1) +const endOfNumber = int8(-2) +const dotInNumber = int8(-3) + +func init() { + floatDigits = make([]int8, 256) + for i := 0; i < len(floatDigits); i++ { + floatDigits[i] = invalidCharForNumber + } + for i := int8('0'); i <= int8('9'); i++ { + floatDigits[i] = i - int8('0') + } + floatDigits[','] = endOfNumber + floatDigits[']'] = endOfNumber + floatDigits['}'] = endOfNumber + floatDigits[' '] = endOfNumber + floatDigits['\t'] = endOfNumber + floatDigits['\n'] = endOfNumber + floatDigits['.'] = dotInNumber +} + +// ReadBigFloat read big.Float +func (iter *Iterator) ReadBigFloat() (ret *big.Float) { + str := iter.readNumberAsString() + if iter.Error != nil && iter.Error != io.EOF { + return nil + } + prec := 64 + if len(str) > prec { + prec = len(str) + } + val, _, err := big.ParseFloat(str, 10, uint(prec), big.ToZero) + if err != nil { + iter.Error = err + return nil + } + return val +} + +// ReadBigInt read big.Int +func (iter *Iterator) ReadBigInt() (ret *big.Int) { + str := iter.readNumberAsString() + if iter.Error != nil && iter.Error != io.EOF { + return nil + } + ret = big.NewInt(0) + var success bool + ret, success = ret.SetString(str, 10) + if !success { + iter.ReportError("ReadBigInt", "invalid big int") + return nil + } + return ret +} + +//ReadFloat32 read float32 +func (iter *Iterator) ReadFloat32() (ret float32) { + c := iter.nextToken() + if c == '-' { + return -iter.readPositiveFloat32() + } + iter.unreadByte() + return iter.readPositiveFloat32() +} + +func (iter *Iterator) readPositiveFloat32() (ret float32) { + i := iter.head + // first char + if i == iter.tail { + return iter.readFloat32SlowPath() + } + c := iter.buf[i] + i++ + ind := floatDigits[c] + switch ind { + case invalidCharForNumber: + return iter.readFloat32SlowPath() + case endOfNumber: + iter.ReportError("readFloat32", "empty number") + return + case dotInNumber: + iter.ReportError("readFloat32", "leading dot is invalid") + return + case 0: + if i == iter.tail { + return iter.readFloat32SlowPath() + } + c = iter.buf[i] + switch c { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + iter.ReportError("readFloat32", "leading zero is invalid") + return + } + } + value := uint64(ind) + // chars before dot +non_decimal_loop: + for ; i < iter.tail; i++ { + c = iter.buf[i] + ind := floatDigits[c] + switch ind { + case invalidCharForNumber: + return iter.readFloat32SlowPath() + case endOfNumber: + iter.head = i + return float32(value) + case dotInNumber: + break non_decimal_loop + } + if value > uint64SafeToMultiple10 { + return iter.readFloat32SlowPath() + } + value = (value << 3) + (value << 1) + uint64(ind) // value = value * 10 + ind; + } + // chars after dot + if c == '.' { + i++ + decimalPlaces := 0 + if i == iter.tail { + return iter.readFloat32SlowPath() + } + for ; i < iter.tail; i++ { + c = iter.buf[i] + ind := floatDigits[c] + switch ind { + case endOfNumber: + if decimalPlaces > 0 && decimalPlaces < len(pow10) { + iter.head = i + return float32(float64(value) / float64(pow10[decimalPlaces])) + } + // too many decimal places + return iter.readFloat32SlowPath() + case invalidCharForNumber, dotInNumber: + return iter.readFloat32SlowPath() + } + decimalPlaces++ + if value > uint64SafeToMultiple10 { + return iter.readFloat32SlowPath() + } + value = (value << 3) + (value << 1) + uint64(ind) + } + } + return iter.readFloat32SlowPath() +} + +func (iter *Iterator) readNumberAsString() (ret string) { + strBuf := [16]byte{} + str := strBuf[0:0] +load_loop: + for { + for i := iter.head; i < iter.tail; i++ { + c := iter.buf[i] + switch c { + case '+', '-', '.', 'e', 'E', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + str = append(str, c) + continue + default: + iter.head = i + break load_loop + } + } + if !iter.loadMore() { + break + } + } + if iter.Error != nil && iter.Error != io.EOF { + return + } + if len(str) == 0 { + iter.ReportError("readNumberAsString", "invalid number") + } + return *(*string)(unsafe.Pointer(&str)) +} + +func (iter *Iterator) readFloat32SlowPath() (ret float32) { + str := iter.readNumberAsString() + if iter.Error != nil && iter.Error != io.EOF { + return + } + errMsg := validateFloat(str) + if errMsg != "" { + iter.ReportError("readFloat32SlowPath", errMsg) + return + } + val, err := strconv.ParseFloat(str, 32) + if err != nil { + iter.Error = err + return + } + return float32(val) +} + +// ReadFloat64 read float64 +func (iter *Iterator) ReadFloat64() (ret float64) { + c := iter.nextToken() + if c == '-' { + return -iter.readPositiveFloat64() + } + iter.unreadByte() + return iter.readPositiveFloat64() +} + +func (iter *Iterator) readPositiveFloat64() (ret float64) { + i := iter.head + // first char + if i == iter.tail { + return iter.readFloat64SlowPath() + } + c := iter.buf[i] + i++ + ind := floatDigits[c] + switch ind { + case invalidCharForNumber: + return iter.readFloat64SlowPath() + case endOfNumber: + iter.ReportError("readFloat64", "empty number") + return + case dotInNumber: + iter.ReportError("readFloat64", "leading dot is invalid") + return + case 0: + if i == iter.tail { + return iter.readFloat64SlowPath() + } + c = iter.buf[i] + switch c { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + iter.ReportError("readFloat64", "leading zero is invalid") + return + } + } + value := uint64(ind) + // chars before dot +non_decimal_loop: + for ; i < iter.tail; i++ { + c = iter.buf[i] + ind := floatDigits[c] + switch ind { + case invalidCharForNumber: + return iter.readFloat64SlowPath() + case endOfNumber: + iter.head = i + return float64(value) + case dotInNumber: + break non_decimal_loop + } + if value > uint64SafeToMultiple10 { + return iter.readFloat64SlowPath() + } + value = (value << 3) + (value << 1) + uint64(ind) // value = value * 10 + ind; + } + // chars after dot + if c == '.' { + i++ + decimalPlaces := 0 + if i == iter.tail { + return iter.readFloat64SlowPath() + } + for ; i < iter.tail; i++ { + c = iter.buf[i] + ind := floatDigits[c] + switch ind { + case endOfNumber: + if decimalPlaces > 0 && decimalPlaces < len(pow10) { + iter.head = i + return float64(value) / float64(pow10[decimalPlaces]) + } + // too many decimal places + return iter.readFloat64SlowPath() + case invalidCharForNumber, dotInNumber: + return iter.readFloat64SlowPath() + } + decimalPlaces++ + if value > uint64SafeToMultiple10 { + return iter.readFloat64SlowPath() + } + value = (value << 3) + (value << 1) + uint64(ind) + } + } + return iter.readFloat64SlowPath() +} + +func (iter *Iterator) readFloat64SlowPath() (ret float64) { + str := iter.readNumberAsString() + if iter.Error != nil && iter.Error != io.EOF { + return + } + errMsg := validateFloat(str) + if errMsg != "" { + iter.ReportError("readFloat64SlowPath", errMsg) + return + } + val, err := strconv.ParseFloat(str, 64) + if err != nil { + iter.Error = err + return + } + return val +} + +func validateFloat(str string) string { + // strconv.ParseFloat is not validating `1.` or `1.e1` + if len(str) == 0 { + return "empty number" + } + if str[0] == '-' { + return "-- is not valid" + } + dotPos := strings.IndexByte(str, '.') + if dotPos != -1 { + if dotPos == len(str)-1 { + return "dot can not be last character" + } + switch str[dotPos+1] { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + default: + return "missing digit after dot" + } + } + return "" +} + +// ReadNumber read json.Number +func (iter *Iterator) ReadNumber() (ret json.Number) { + return json.Number(iter.readNumberAsString()) +} diff --git a/vendor/github.com/json-iterator/go/iter_int.go b/vendor/github.com/json-iterator/go/iter_int.go new file mode 100644 index 0000000000000..2142320355e87 --- /dev/null +++ b/vendor/github.com/json-iterator/go/iter_int.go @@ -0,0 +1,345 @@ +package jsoniter + +import ( + "math" + "strconv" +) + +var intDigits []int8 + +const uint32SafeToMultiply10 = uint32(0xffffffff)/10 - 1 +const uint64SafeToMultiple10 = uint64(0xffffffffffffffff)/10 - 1 + +func init() { + intDigits = make([]int8, 256) + for i := 0; i < len(intDigits); i++ { + intDigits[i] = invalidCharForNumber + } + for i := int8('0'); i <= int8('9'); i++ { + intDigits[i] = i - int8('0') + } +} + +// ReadUint read uint +func (iter *Iterator) ReadUint() uint { + if strconv.IntSize == 32 { + return uint(iter.ReadUint32()) + } + return uint(iter.ReadUint64()) +} + +// ReadInt read int +func (iter *Iterator) ReadInt() int { + if strconv.IntSize == 32 { + return int(iter.ReadInt32()) + } + return int(iter.ReadInt64()) +} + +// ReadInt8 read int8 +func (iter *Iterator) ReadInt8() (ret int8) { + c := iter.nextToken() + if c == '-' { + val := iter.readUint32(iter.readByte()) + if val > math.MaxInt8+1 { + iter.ReportError("ReadInt8", "overflow: "+strconv.FormatInt(int64(val), 10)) + return + } + return -int8(val) + } + val := iter.readUint32(c) + if val > math.MaxInt8 { + iter.ReportError("ReadInt8", "overflow: "+strconv.FormatInt(int64(val), 10)) + return + } + return int8(val) +} + +// ReadUint8 read uint8 +func (iter *Iterator) ReadUint8() (ret uint8) { + val := iter.readUint32(iter.nextToken()) + if val > math.MaxUint8 { + iter.ReportError("ReadUint8", "overflow: "+strconv.FormatInt(int64(val), 10)) + return + } + return uint8(val) +} + +// ReadInt16 read int16 +func (iter *Iterator) ReadInt16() (ret int16) { + c := iter.nextToken() + if c == '-' { + val := iter.readUint32(iter.readByte()) + if val > math.MaxInt16+1 { + iter.ReportError("ReadInt16", "overflow: "+strconv.FormatInt(int64(val), 10)) + return + } + return -int16(val) + } + val := iter.readUint32(c) + if val > math.MaxInt16 { + iter.ReportError("ReadInt16", "overflow: "+strconv.FormatInt(int64(val), 10)) + return + } + return int16(val) +} + +// ReadUint16 read uint16 +func (iter *Iterator) ReadUint16() (ret uint16) { + val := iter.readUint32(iter.nextToken()) + if val > math.MaxUint16 { + iter.ReportError("ReadUint16", "overflow: "+strconv.FormatInt(int64(val), 10)) + return + } + return uint16(val) +} + +// ReadInt32 read int32 +func (iter *Iterator) ReadInt32() (ret int32) { + c := iter.nextToken() + if c == '-' { + val := iter.readUint32(iter.readByte()) + if val > math.MaxInt32+1 { + iter.ReportError("ReadInt32", "overflow: "+strconv.FormatInt(int64(val), 10)) + return + } + return -int32(val) + } + val := iter.readUint32(c) + if val > math.MaxInt32 { + iter.ReportError("ReadInt32", "overflow: "+strconv.FormatInt(int64(val), 10)) + return + } + return int32(val) +} + +// ReadUint32 read uint32 +func (iter *Iterator) ReadUint32() (ret uint32) { + return iter.readUint32(iter.nextToken()) +} + +func (iter *Iterator) readUint32(c byte) (ret uint32) { + ind := intDigits[c] + if ind == 0 { + iter.assertInteger() + return 0 // single zero + } + if ind == invalidCharForNumber { + iter.ReportError("readUint32", "unexpected character: "+string([]byte{byte(ind)})) + return + } + value := uint32(ind) + if iter.tail-iter.head > 10 { + i := iter.head + ind2 := intDigits[iter.buf[i]] + if ind2 == invalidCharForNumber { + iter.head = i + iter.assertInteger() + return value + } + i++ + ind3 := intDigits[iter.buf[i]] + if ind3 == invalidCharForNumber { + iter.head = i + iter.assertInteger() + return value*10 + uint32(ind2) + } + //iter.head = i + 1 + //value = value * 100 + uint32(ind2) * 10 + uint32(ind3) + i++ + ind4 := intDigits[iter.buf[i]] + if ind4 == invalidCharForNumber { + iter.head = i + iter.assertInteger() + return value*100 + uint32(ind2)*10 + uint32(ind3) + } + i++ + ind5 := intDigits[iter.buf[i]] + if ind5 == invalidCharForNumber { + iter.head = i + iter.assertInteger() + return value*1000 + uint32(ind2)*100 + uint32(ind3)*10 + uint32(ind4) + } + i++ + ind6 := intDigits[iter.buf[i]] + if ind6 == invalidCharForNumber { + iter.head = i + iter.assertInteger() + return value*10000 + uint32(ind2)*1000 + uint32(ind3)*100 + uint32(ind4)*10 + uint32(ind5) + } + i++ + ind7 := intDigits[iter.buf[i]] + if ind7 == invalidCharForNumber { + iter.head = i + iter.assertInteger() + return value*100000 + uint32(ind2)*10000 + uint32(ind3)*1000 + uint32(ind4)*100 + uint32(ind5)*10 + uint32(ind6) + } + i++ + ind8 := intDigits[iter.buf[i]] + if ind8 == invalidCharForNumber { + iter.head = i + iter.assertInteger() + return value*1000000 + uint32(ind2)*100000 + uint32(ind3)*10000 + uint32(ind4)*1000 + uint32(ind5)*100 + uint32(ind6)*10 + uint32(ind7) + } + i++ + ind9 := intDigits[iter.buf[i]] + value = value*10000000 + uint32(ind2)*1000000 + uint32(ind3)*100000 + uint32(ind4)*10000 + uint32(ind5)*1000 + uint32(ind6)*100 + uint32(ind7)*10 + uint32(ind8) + iter.head = i + if ind9 == invalidCharForNumber { + iter.assertInteger() + return value + } + } + for { + for i := iter.head; i < iter.tail; i++ { + ind = intDigits[iter.buf[i]] + if ind == invalidCharForNumber { + iter.head = i + iter.assertInteger() + return value + } + if value > uint32SafeToMultiply10 { + value2 := (value << 3) + (value << 1) + uint32(ind) + if value2 < value { + iter.ReportError("readUint32", "overflow") + return + } + value = value2 + continue + } + value = (value << 3) + (value << 1) + uint32(ind) + } + if !iter.loadMore() { + iter.assertInteger() + return value + } + } +} + +// ReadInt64 read int64 +func (iter *Iterator) ReadInt64() (ret int64) { + c := iter.nextToken() + if c == '-' { + val := iter.readUint64(iter.readByte()) + if val > math.MaxInt64+1 { + iter.ReportError("ReadInt64", "overflow: "+strconv.FormatUint(uint64(val), 10)) + return + } + return -int64(val) + } + val := iter.readUint64(c) + if val > math.MaxInt64 { + iter.ReportError("ReadInt64", "overflow: "+strconv.FormatUint(uint64(val), 10)) + return + } + return int64(val) +} + +// ReadUint64 read uint64 +func (iter *Iterator) ReadUint64() uint64 { + return iter.readUint64(iter.nextToken()) +} + +func (iter *Iterator) readUint64(c byte) (ret uint64) { + ind := intDigits[c] + if ind == 0 { + iter.assertInteger() + return 0 // single zero + } + if ind == invalidCharForNumber { + iter.ReportError("readUint64", "unexpected character: "+string([]byte{byte(ind)})) + return + } + value := uint64(ind) + if iter.tail-iter.head > 10 { + i := iter.head + ind2 := intDigits[iter.buf[i]] + if ind2 == invalidCharForNumber { + iter.head = i + iter.assertInteger() + return value + } + i++ + ind3 := intDigits[iter.buf[i]] + if ind3 == invalidCharForNumber { + iter.head = i + iter.assertInteger() + return value*10 + uint64(ind2) + } + //iter.head = i + 1 + //value = value * 100 + uint32(ind2) * 10 + uint32(ind3) + i++ + ind4 := intDigits[iter.buf[i]] + if ind4 == invalidCharForNumber { + iter.head = i + iter.assertInteger() + return value*100 + uint64(ind2)*10 + uint64(ind3) + } + i++ + ind5 := intDigits[iter.buf[i]] + if ind5 == invalidCharForNumber { + iter.head = i + iter.assertInteger() + return value*1000 + uint64(ind2)*100 + uint64(ind3)*10 + uint64(ind4) + } + i++ + ind6 := intDigits[iter.buf[i]] + if ind6 == invalidCharForNumber { + iter.head = i + iter.assertInteger() + return value*10000 + uint64(ind2)*1000 + uint64(ind3)*100 + uint64(ind4)*10 + uint64(ind5) + } + i++ + ind7 := intDigits[iter.buf[i]] + if ind7 == invalidCharForNumber { + iter.head = i + iter.assertInteger() + return value*100000 + uint64(ind2)*10000 + uint64(ind3)*1000 + uint64(ind4)*100 + uint64(ind5)*10 + uint64(ind6) + } + i++ + ind8 := intDigits[iter.buf[i]] + if ind8 == invalidCharForNumber { + iter.head = i + iter.assertInteger() + return value*1000000 + uint64(ind2)*100000 + uint64(ind3)*10000 + uint64(ind4)*1000 + uint64(ind5)*100 + uint64(ind6)*10 + uint64(ind7) + } + i++ + ind9 := intDigits[iter.buf[i]] + value = value*10000000 + uint64(ind2)*1000000 + uint64(ind3)*100000 + uint64(ind4)*10000 + uint64(ind5)*1000 + uint64(ind6)*100 + uint64(ind7)*10 + uint64(ind8) + iter.head = i + if ind9 == invalidCharForNumber { + iter.assertInteger() + return value + } + } + for { + for i := iter.head; i < iter.tail; i++ { + ind = intDigits[iter.buf[i]] + if ind == invalidCharForNumber { + iter.head = i + iter.assertInteger() + return value + } + if value > uint64SafeToMultiple10 { + value2 := (value << 3) + (value << 1) + uint64(ind) + if value2 < value { + iter.ReportError("readUint64", "overflow") + return + } + value = value2 + continue + } + value = (value << 3) + (value << 1) + uint64(ind) + } + if !iter.loadMore() { + iter.assertInteger() + return value + } + } +} + +func (iter *Iterator) assertInteger() { + if iter.head < len(iter.buf) && iter.buf[iter.head] == '.' { + iter.ReportError("assertInteger", "can not decode float as int") + } +} diff --git a/vendor/github.com/json-iterator/go/iter_object.go b/vendor/github.com/json-iterator/go/iter_object.go new file mode 100644 index 0000000000000..b65137114f65b --- /dev/null +++ b/vendor/github.com/json-iterator/go/iter_object.go @@ -0,0 +1,267 @@ +package jsoniter + +import ( + "fmt" + "strings" +) + +// ReadObject read one field from object. +// If object ended, returns empty string. +// Otherwise, returns the field name. +func (iter *Iterator) ReadObject() (ret string) { + c := iter.nextToken() + switch c { + case 'n': + iter.skipThreeBytes('u', 'l', 'l') + return "" // null + case '{': + c = iter.nextToken() + if c == '"' { + iter.unreadByte() + field := iter.ReadString() + c = iter.nextToken() + if c != ':' { + iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c})) + } + return field + } + if c == '}' { + return "" // end of object + } + iter.ReportError("ReadObject", `expect " after {, but found `+string([]byte{c})) + return + case ',': + field := iter.ReadString() + c = iter.nextToken() + if c != ':' { + iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c})) + } + return field + case '}': + return "" // end of object + default: + iter.ReportError("ReadObject", fmt.Sprintf(`expect { or , or } or n, but found %s`, string([]byte{c}))) + return + } +} + +// CaseInsensitive +func (iter *Iterator) readFieldHash() int64 { + hash := int64(0x811c9dc5) + c := iter.nextToken() + if c != '"' { + iter.ReportError("readFieldHash", `expect ", but found `+string([]byte{c})) + return 0 + } + for { + for i := iter.head; i < iter.tail; i++ { + // require ascii string and no escape + b := iter.buf[i] + if b == '\\' { + iter.head = i + for _, b := range iter.readStringSlowPath() { + if 'A' <= b && b <= 'Z' && !iter.cfg.caseSensitive { + b += 'a' - 'A' + } + hash ^= int64(b) + hash *= 0x1000193 + } + c = iter.nextToken() + if c != ':' { + iter.ReportError("readFieldHash", `expect :, but found `+string([]byte{c})) + return 0 + } + return hash + } + if b == '"' { + iter.head = i + 1 + c = iter.nextToken() + if c != ':' { + iter.ReportError("readFieldHash", `expect :, but found `+string([]byte{c})) + return 0 + } + return hash + } + if 'A' <= b && b <= 'Z' && !iter.cfg.caseSensitive { + b += 'a' - 'A' + } + hash ^= int64(b) + hash *= 0x1000193 + } + if !iter.loadMore() { + iter.ReportError("readFieldHash", `incomplete field name`) + return 0 + } + } +} + +func calcHash(str string, caseSensitive bool) int64 { + if !caseSensitive { + str = strings.ToLower(str) + } + hash := int64(0x811c9dc5) + for _, b := range []byte(str) { + hash ^= int64(b) + hash *= 0x1000193 + } + return int64(hash) +} + +// ReadObjectCB read object with callback, the key is ascii only and field name not copied +func (iter *Iterator) ReadObjectCB(callback func(*Iterator, string) bool) bool { + c := iter.nextToken() + var field string + if c == '{' { + if !iter.incrementDepth() { + return false + } + c = iter.nextToken() + if c == '"' { + iter.unreadByte() + field = iter.ReadString() + c = iter.nextToken() + if c != ':' { + iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c})) + } + if !callback(iter, field) { + iter.decrementDepth() + return false + } + c = iter.nextToken() + for c == ',' { + field = iter.ReadString() + c = iter.nextToken() + if c != ':' { + iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c})) + } + if !callback(iter, field) { + iter.decrementDepth() + return false + } + c = iter.nextToken() + } + if c != '}' { + iter.ReportError("ReadObjectCB", `object not ended with }`) + iter.decrementDepth() + return false + } + return iter.decrementDepth() + } + if c == '}' { + return iter.decrementDepth() + } + iter.ReportError("ReadObjectCB", `expect " after }, but found `+string([]byte{c})) + iter.decrementDepth() + return false + } + if c == 'n' { + iter.skipThreeBytes('u', 'l', 'l') + return true // null + } + iter.ReportError("ReadObjectCB", `expect { or n, but found `+string([]byte{c})) + return false +} + +// ReadMapCB read map with callback, the key can be any string +func (iter *Iterator) ReadMapCB(callback func(*Iterator, string) bool) bool { + c := iter.nextToken() + if c == '{' { + if !iter.incrementDepth() { + return false + } + c = iter.nextToken() + if c == '"' { + iter.unreadByte() + field := iter.ReadString() + if iter.nextToken() != ':' { + iter.ReportError("ReadMapCB", "expect : after object field, but found "+string([]byte{c})) + iter.decrementDepth() + return false + } + if !callback(iter, field) { + iter.decrementDepth() + return false + } + c = iter.nextToken() + for c == ',' { + field = iter.ReadString() + if iter.nextToken() != ':' { + iter.ReportError("ReadMapCB", "expect : after object field, but found "+string([]byte{c})) + iter.decrementDepth() + return false + } + if !callback(iter, field) { + iter.decrementDepth() + return false + } + c = iter.nextToken() + } + if c != '}' { + iter.ReportError("ReadMapCB", `object not ended with }`) + iter.decrementDepth() + return false + } + return iter.decrementDepth() + } + if c == '}' { + return iter.decrementDepth() + } + iter.ReportError("ReadMapCB", `expect " after }, but found `+string([]byte{c})) + iter.decrementDepth() + return false + } + if c == 'n' { + iter.skipThreeBytes('u', 'l', 'l') + return true // null + } + iter.ReportError("ReadMapCB", `expect { or n, but found `+string([]byte{c})) + return false +} + +func (iter *Iterator) readObjectStart() bool { + c := iter.nextToken() + if c == '{' { + c = iter.nextToken() + if c == '}' { + return false + } + iter.unreadByte() + return true + } else if c == 'n' { + iter.skipThreeBytes('u', 'l', 'l') + return false + } + iter.ReportError("readObjectStart", "expect { or n, but found "+string([]byte{c})) + return false +} + +func (iter *Iterator) readObjectFieldAsBytes() (ret []byte) { + str := iter.ReadStringAsSlice() + if iter.skipWhitespacesWithoutLoadMore() { + if ret == nil { + ret = make([]byte, len(str)) + copy(ret, str) + } + if !iter.loadMore() { + return + } + } + if iter.buf[iter.head] != ':' { + iter.ReportError("readObjectFieldAsBytes", "expect : after object field, but found "+string([]byte{iter.buf[iter.head]})) + return + } + iter.head++ + if iter.skipWhitespacesWithoutLoadMore() { + if ret == nil { + ret = make([]byte, len(str)) + copy(ret, str) + } + if !iter.loadMore() { + return + } + } + if ret == nil { + return str + } + return ret +} diff --git a/vendor/github.com/json-iterator/go/iter_skip.go b/vendor/github.com/json-iterator/go/iter_skip.go new file mode 100644 index 0000000000000..e91eefb15becf --- /dev/null +++ b/vendor/github.com/json-iterator/go/iter_skip.go @@ -0,0 +1,130 @@ +package jsoniter + +import "fmt" + +// ReadNil reads a json object as nil and +// returns whether it's a nil or not +func (iter *Iterator) ReadNil() (ret bool) { + c := iter.nextToken() + if c == 'n' { + iter.skipThreeBytes('u', 'l', 'l') // null + return true + } + iter.unreadByte() + return false +} + +// ReadBool reads a json object as BoolValue +func (iter *Iterator) ReadBool() (ret bool) { + c := iter.nextToken() + if c == 't' { + iter.skipThreeBytes('r', 'u', 'e') + return true + } + if c == 'f' { + iter.skipFourBytes('a', 'l', 's', 'e') + return false + } + iter.ReportError("ReadBool", "expect t or f, but found "+string([]byte{c})) + return +} + +// SkipAndReturnBytes skip next JSON element, and return its content as []byte. +// The []byte can be kept, it is a copy of data. +func (iter *Iterator) SkipAndReturnBytes() []byte { + iter.startCapture(iter.head) + iter.Skip() + return iter.stopCapture() +} + +// SkipAndAppendBytes skips next JSON element and appends its content to +// buffer, returning the result. +func (iter *Iterator) SkipAndAppendBytes(buf []byte) []byte { + iter.startCaptureTo(buf, iter.head) + iter.Skip() + return iter.stopCapture() +} + +func (iter *Iterator) startCaptureTo(buf []byte, captureStartedAt int) { + if iter.captured != nil { + panic("already in capture mode") + } + iter.captureStartedAt = captureStartedAt + iter.captured = buf +} + +func (iter *Iterator) startCapture(captureStartedAt int) { + iter.startCaptureTo(make([]byte, 0, 32), captureStartedAt) +} + +func (iter *Iterator) stopCapture() []byte { + if iter.captured == nil { + panic("not in capture mode") + } + captured := iter.captured + remaining := iter.buf[iter.captureStartedAt:iter.head] + iter.captureStartedAt = -1 + iter.captured = nil + return append(captured, remaining...) +} + +// Skip skips a json object and positions to relatively the next json object +func (iter *Iterator) Skip() { + c := iter.nextToken() + switch c { + case '"': + iter.skipString() + case 'n': + iter.skipThreeBytes('u', 'l', 'l') // null + case 't': + iter.skipThreeBytes('r', 'u', 'e') // true + case 'f': + iter.skipFourBytes('a', 'l', 's', 'e') // false + case '0': + iter.unreadByte() + iter.ReadFloat32() + case '-', '1', '2', '3', '4', '5', '6', '7', '8', '9': + iter.skipNumber() + case '[': + iter.skipArray() + case '{': + iter.skipObject() + default: + iter.ReportError("Skip", fmt.Sprintf("do not know how to skip: %v", c)) + return + } +} + +func (iter *Iterator) skipFourBytes(b1, b2, b3, b4 byte) { + if iter.readByte() != b1 { + iter.ReportError("skipFourBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3, b4}))) + return + } + if iter.readByte() != b2 { + iter.ReportError("skipFourBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3, b4}))) + return + } + if iter.readByte() != b3 { + iter.ReportError("skipFourBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3, b4}))) + return + } + if iter.readByte() != b4 { + iter.ReportError("skipFourBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3, b4}))) + return + } +} + +func (iter *Iterator) skipThreeBytes(b1, b2, b3 byte) { + if iter.readByte() != b1 { + iter.ReportError("skipThreeBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3}))) + return + } + if iter.readByte() != b2 { + iter.ReportError("skipThreeBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3}))) + return + } + if iter.readByte() != b3 { + iter.ReportError("skipThreeBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3}))) + return + } +} diff --git a/vendor/github.com/json-iterator/go/iter_skip_sloppy.go b/vendor/github.com/json-iterator/go/iter_skip_sloppy.go new file mode 100644 index 0000000000000..9303de41e4005 --- /dev/null +++ b/vendor/github.com/json-iterator/go/iter_skip_sloppy.go @@ -0,0 +1,163 @@ +//+build jsoniter_sloppy + +package jsoniter + +// sloppy but faster implementation, do not validate the input json + +func (iter *Iterator) skipNumber() { + for { + for i := iter.head; i < iter.tail; i++ { + c := iter.buf[i] + switch c { + case ' ', '\n', '\r', '\t', ',', '}', ']': + iter.head = i + return + } + } + if !iter.loadMore() { + return + } + } +} + +func (iter *Iterator) skipArray() { + level := 1 + if !iter.incrementDepth() { + return + } + for { + for i := iter.head; i < iter.tail; i++ { + switch iter.buf[i] { + case '"': // If inside string, skip it + iter.head = i + 1 + iter.skipString() + i = iter.head - 1 // it will be i++ soon + case '[': // If open symbol, increase level + level++ + if !iter.incrementDepth() { + return + } + case ']': // If close symbol, increase level + level-- + if !iter.decrementDepth() { + return + } + + // If we have returned to the original level, we're done + if level == 0 { + iter.head = i + 1 + return + } + } + } + if !iter.loadMore() { + iter.ReportError("skipObject", "incomplete array") + return + } + } +} + +func (iter *Iterator) skipObject() { + level := 1 + if !iter.incrementDepth() { + return + } + + for { + for i := iter.head; i < iter.tail; i++ { + switch iter.buf[i] { + case '"': // If inside string, skip it + iter.head = i + 1 + iter.skipString() + i = iter.head - 1 // it will be i++ soon + case '{': // If open symbol, increase level + level++ + if !iter.incrementDepth() { + return + } + case '}': // If close symbol, increase level + level-- + if !iter.decrementDepth() { + return + } + + // If we have returned to the original level, we're done + if level == 0 { + iter.head = i + 1 + return + } + } + } + if !iter.loadMore() { + iter.ReportError("skipObject", "incomplete object") + return + } + } +} + +func (iter *Iterator) skipString() { + for { + end, escaped := iter.findStringEnd() + if end == -1 { + if !iter.loadMore() { + iter.ReportError("skipString", "incomplete string") + return + } + if escaped { + iter.head = 1 // skip the first char as last char read is \ + } + } else { + iter.head = end + return + } + } +} + +// adapted from: https://github.com/buger/jsonparser/blob/master/parser.go +// Tries to find the end of string +// Support if string contains escaped quote symbols. +func (iter *Iterator) findStringEnd() (int, bool) { + escaped := false + for i := iter.head; i < iter.tail; i++ { + c := iter.buf[i] + if c == '"' { + if !escaped { + return i + 1, false + } + j := i - 1 + for { + if j < iter.head || iter.buf[j] != '\\' { + // even number of backslashes + // either end of buffer, or " found + return i + 1, true + } + j-- + if j < iter.head || iter.buf[j] != '\\' { + // odd number of backslashes + // it is \" or \\\" + break + } + j-- + } + } else if c == '\\' { + escaped = true + } + } + j := iter.tail - 1 + for { + if j < iter.head || iter.buf[j] != '\\' { + // even number of backslashes + // either end of buffer, or " found + return -1, false // do not end with \ + } + j-- + if j < iter.head || iter.buf[j] != '\\' { + // odd number of backslashes + // it is \" or \\\" + break + } + j-- + + } + return -1, true // end with \ +} diff --git a/vendor/github.com/json-iterator/go/iter_skip_strict.go b/vendor/github.com/json-iterator/go/iter_skip_strict.go new file mode 100644 index 0000000000000..6cf66d0438dbe --- /dev/null +++ b/vendor/github.com/json-iterator/go/iter_skip_strict.go @@ -0,0 +1,99 @@ +//+build !jsoniter_sloppy + +package jsoniter + +import ( + "fmt" + "io" +) + +func (iter *Iterator) skipNumber() { + if !iter.trySkipNumber() { + iter.unreadByte() + if iter.Error != nil && iter.Error != io.EOF { + return + } + iter.ReadFloat64() + if iter.Error != nil && iter.Error != io.EOF { + iter.Error = nil + iter.ReadBigFloat() + } + } +} + +func (iter *Iterator) trySkipNumber() bool { + dotFound := false + for i := iter.head; i < iter.tail; i++ { + c := iter.buf[i] + switch c { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + case '.': + if dotFound { + iter.ReportError("validateNumber", `more than one dot found in number`) + return true // already failed + } + if i+1 == iter.tail { + return false + } + c = iter.buf[i+1] + switch c { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + default: + iter.ReportError("validateNumber", `missing digit after dot`) + return true // already failed + } + dotFound = true + default: + switch c { + case ',', ']', '}', ' ', '\t', '\n', '\r': + if iter.head == i { + return false // if - without following digits + } + iter.head = i + return true // must be valid + } + return false // may be invalid + } + } + return false +} + +func (iter *Iterator) skipString() { + if !iter.trySkipString() { + iter.unreadByte() + iter.ReadString() + } +} + +func (iter *Iterator) trySkipString() bool { + for i := iter.head; i < iter.tail; i++ { + c := iter.buf[i] + if c == '"' { + iter.head = i + 1 + return true // valid + } else if c == '\\' { + return false + } else if c < ' ' { + iter.ReportError("trySkipString", + fmt.Sprintf(`invalid control character found: %d`, c)) + return true // already failed + } + } + return false +} + +func (iter *Iterator) skipObject() { + iter.unreadByte() + iter.ReadObjectCB(func(iter *Iterator, field string) bool { + iter.Skip() + return true + }) +} + +func (iter *Iterator) skipArray() { + iter.unreadByte() + iter.ReadArrayCB(func(iter *Iterator) bool { + iter.Skip() + return true + }) +} diff --git a/vendor/github.com/json-iterator/go/iter_str.go b/vendor/github.com/json-iterator/go/iter_str.go new file mode 100644 index 0000000000000..adc487ea80483 --- /dev/null +++ b/vendor/github.com/json-iterator/go/iter_str.go @@ -0,0 +1,215 @@ +package jsoniter + +import ( + "fmt" + "unicode/utf16" +) + +// ReadString read string from iterator +func (iter *Iterator) ReadString() (ret string) { + c := iter.nextToken() + if c == '"' { + for i := iter.head; i < iter.tail; i++ { + c := iter.buf[i] + if c == '"' { + ret = string(iter.buf[iter.head:i]) + iter.head = i + 1 + return ret + } else if c == '\\' { + break + } else if c < ' ' { + iter.ReportError("ReadString", + fmt.Sprintf(`invalid control character found: %d`, c)) + return + } + } + return iter.readStringSlowPath() + } else if c == 'n' { + iter.skipThreeBytes('u', 'l', 'l') + return "" + } + iter.ReportError("ReadString", `expects " or n, but found `+string([]byte{c})) + return +} + +func (iter *Iterator) readStringSlowPath() (ret string) { + var str []byte + var c byte + for iter.Error == nil { + c = iter.readByte() + if c == '"' { + return string(str) + } + if c == '\\' { + c = iter.readByte() + str = iter.readEscapedChar(c, str) + } else { + str = append(str, c) + } + } + iter.ReportError("readStringSlowPath", "unexpected end of input") + return +} + +func (iter *Iterator) readEscapedChar(c byte, str []byte) []byte { + switch c { + case 'u': + r := iter.readU4() + if utf16.IsSurrogate(r) { + c = iter.readByte() + if iter.Error != nil { + return nil + } + if c != '\\' { + iter.unreadByte() + str = appendRune(str, r) + return str + } + c = iter.readByte() + if iter.Error != nil { + return nil + } + if c != 'u' { + str = appendRune(str, r) + return iter.readEscapedChar(c, str) + } + r2 := iter.readU4() + if iter.Error != nil { + return nil + } + combined := utf16.DecodeRune(r, r2) + if combined == '\uFFFD' { + str = appendRune(str, r) + str = appendRune(str, r2) + } else { + str = appendRune(str, combined) + } + } else { + str = appendRune(str, r) + } + case '"': + str = append(str, '"') + case '\\': + str = append(str, '\\') + case '/': + str = append(str, '/') + case 'b': + str = append(str, '\b') + case 'f': + str = append(str, '\f') + case 'n': + str = append(str, '\n') + case 'r': + str = append(str, '\r') + case 't': + str = append(str, '\t') + default: + iter.ReportError("readEscapedChar", + `invalid escape char after \`) + return nil + } + return str +} + +// ReadStringAsSlice read string from iterator without copying into string form. +// The []byte can not be kept, as it will change after next iterator call. +func (iter *Iterator) ReadStringAsSlice() (ret []byte) { + c := iter.nextToken() + if c == '"' { + for i := iter.head; i < iter.tail; i++ { + // require ascii string and no escape + // for: field name, base64, number + if iter.buf[i] == '"' { + // fast path: reuse the underlying buffer + ret = iter.buf[iter.head:i] + iter.head = i + 1 + return ret + } + } + readLen := iter.tail - iter.head + copied := make([]byte, readLen, readLen*2) + copy(copied, iter.buf[iter.head:iter.tail]) + iter.head = iter.tail + for iter.Error == nil { + c := iter.readByte() + if c == '"' { + return copied + } + copied = append(copied, c) + } + return copied + } + iter.ReportError("ReadStringAsSlice", `expects " or n, but found `+string([]byte{c})) + return +} + +func (iter *Iterator) readU4() (ret rune) { + for i := 0; i < 4; i++ { + c := iter.readByte() + if iter.Error != nil { + return + } + if c >= '0' && c <= '9' { + ret = ret*16 + rune(c-'0') + } else if c >= 'a' && c <= 'f' { + ret = ret*16 + rune(c-'a'+10) + } else if c >= 'A' && c <= 'F' { + ret = ret*16 + rune(c-'A'+10) + } else { + iter.ReportError("readU4", "expects 0~9 or a~f, but found "+string([]byte{c})) + return + } + } + return ret +} + +const ( + t1 = 0x00 // 0000 0000 + tx = 0x80 // 1000 0000 + t2 = 0xC0 // 1100 0000 + t3 = 0xE0 // 1110 0000 + t4 = 0xF0 // 1111 0000 + t5 = 0xF8 // 1111 1000 + + maskx = 0x3F // 0011 1111 + mask2 = 0x1F // 0001 1111 + mask3 = 0x0F // 0000 1111 + mask4 = 0x07 // 0000 0111 + + rune1Max = 1<<7 - 1 + rune2Max = 1<<11 - 1 + rune3Max = 1<<16 - 1 + + surrogateMin = 0xD800 + surrogateMax = 0xDFFF + + maxRune = '\U0010FFFF' // Maximum valid Unicode code point. + runeError = '\uFFFD' // the "error" Rune or "Unicode replacement character" +) + +func appendRune(p []byte, r rune) []byte { + // Negative values are erroneous. Making it unsigned addresses the problem. + switch i := uint32(r); { + case i <= rune1Max: + p = append(p, byte(r)) + return p + case i <= rune2Max: + p = append(p, t2|byte(r>>6)) + p = append(p, tx|byte(r)&maskx) + return p + case i > maxRune, surrogateMin <= i && i <= surrogateMax: + r = runeError + fallthrough + case i <= rune3Max: + p = append(p, t3|byte(r>>12)) + p = append(p, tx|byte(r>>6)&maskx) + p = append(p, tx|byte(r)&maskx) + return p + default: + p = append(p, t4|byte(r>>18)) + p = append(p, tx|byte(r>>12)&maskx) + p = append(p, tx|byte(r>>6)&maskx) + p = append(p, tx|byte(r)&maskx) + return p + } +} diff --git a/vendor/github.com/json-iterator/go/jsoniter.go b/vendor/github.com/json-iterator/go/jsoniter.go new file mode 100644 index 0000000000000..c2934f916eb30 --- /dev/null +++ b/vendor/github.com/json-iterator/go/jsoniter.go @@ -0,0 +1,18 @@ +// Package jsoniter implements encoding and decoding of JSON as defined in +// RFC 4627 and provides interfaces with identical syntax of standard lib encoding/json. +// Converting from encoding/json to jsoniter is no more than replacing the package with jsoniter +// and variable type declarations (if any). +// jsoniter interfaces gives 100% compatibility with code using standard lib. +// +// "JSON and Go" +// (https://golang.org/doc/articles/json_and_go.html) +// gives a description of how Marshal/Unmarshal operate +// between arbitrary or predefined json objects and bytes, +// and it applies to jsoniter.Marshal/Unmarshal as well. +// +// Besides, jsoniter.Iterator provides a different set of interfaces +// iterating given bytes/string/reader +// and yielding parsed elements one by one. +// This set of interfaces reads input as required and gives +// better performance. +package jsoniter diff --git a/vendor/github.com/json-iterator/go/pool.go b/vendor/github.com/json-iterator/go/pool.go new file mode 100644 index 0000000000000..e2389b56cfff3 --- /dev/null +++ b/vendor/github.com/json-iterator/go/pool.go @@ -0,0 +1,42 @@ +package jsoniter + +import ( + "io" +) + +// IteratorPool a thread safe pool of iterators with same configuration +type IteratorPool interface { + BorrowIterator(data []byte) *Iterator + ReturnIterator(iter *Iterator) +} + +// StreamPool a thread safe pool of streams with same configuration +type StreamPool interface { + BorrowStream(writer io.Writer) *Stream + ReturnStream(stream *Stream) +} + +func (cfg *frozenConfig) BorrowStream(writer io.Writer) *Stream { + stream := cfg.streamPool.Get().(*Stream) + stream.Reset(writer) + return stream +} + +func (cfg *frozenConfig) ReturnStream(stream *Stream) { + stream.out = nil + stream.Error = nil + stream.Attachment = nil + cfg.streamPool.Put(stream) +} + +func (cfg *frozenConfig) BorrowIterator(data []byte) *Iterator { + iter := cfg.iteratorPool.Get().(*Iterator) + iter.ResetBytes(data) + return iter +} + +func (cfg *frozenConfig) ReturnIterator(iter *Iterator) { + iter.Error = nil + iter.Attachment = nil + cfg.iteratorPool.Put(iter) +} diff --git a/vendor/github.com/json-iterator/go/reflect.go b/vendor/github.com/json-iterator/go/reflect.go new file mode 100644 index 0000000000000..74974ba74b067 --- /dev/null +++ b/vendor/github.com/json-iterator/go/reflect.go @@ -0,0 +1,337 @@ +package jsoniter + +import ( + "fmt" + "reflect" + "unsafe" + + "github.com/modern-go/reflect2" +) + +// ValDecoder is an internal type registered to cache as needed. +// Don't confuse jsoniter.ValDecoder with json.Decoder. +// For json.Decoder's adapter, refer to jsoniter.AdapterDecoder(todo link). +// +// Reflection on type to create decoders, which is then cached +// Reflection on value is avoided as we can, as the reflect.Value itself will allocate, with following exceptions +// 1. create instance of new value, for example *int will need a int to be allocated +// 2. append to slice, if the existing cap is not enough, allocate will be done using Reflect.New +// 3. assignment to map, both key and value will be reflect.Value +// For a simple struct binding, it will be reflect.Value free and allocation free +type ValDecoder interface { + Decode(ptr unsafe.Pointer, iter *Iterator) +} + +// ValEncoder is an internal type registered to cache as needed. +// Don't confuse jsoniter.ValEncoder with json.Encoder. +// For json.Encoder's adapter, refer to jsoniter.AdapterEncoder(todo godoc link). +type ValEncoder interface { + IsEmpty(ptr unsafe.Pointer) bool + Encode(ptr unsafe.Pointer, stream *Stream) +} + +type checkIsEmpty interface { + IsEmpty(ptr unsafe.Pointer) bool +} + +type ctx struct { + *frozenConfig + prefix string + encoders map[reflect2.Type]ValEncoder + decoders map[reflect2.Type]ValDecoder +} + +func (b *ctx) caseSensitive() bool { + if b.frozenConfig == nil { + // default is case-insensitive + return false + } + return b.frozenConfig.caseSensitive +} + +func (b *ctx) append(prefix string) *ctx { + return &ctx{ + frozenConfig: b.frozenConfig, + prefix: b.prefix + " " + prefix, + encoders: b.encoders, + decoders: b.decoders, + } +} + +// ReadVal copy the underlying JSON into go interface, same as json.Unmarshal +func (iter *Iterator) ReadVal(obj interface{}) { + depth := iter.depth + cacheKey := reflect2.RTypeOf(obj) + decoder := iter.cfg.getDecoderFromCache(cacheKey) + if decoder == nil { + typ := reflect2.TypeOf(obj) + if typ.Kind() != reflect.Ptr { + iter.ReportError("ReadVal", "can only unmarshal into pointer") + return + } + decoder = iter.cfg.DecoderOf(typ) + } + ptr := reflect2.PtrOf(obj) + if ptr == nil { + iter.ReportError("ReadVal", "can not read into nil pointer") + return + } + decoder.Decode(ptr, iter) + if iter.depth != depth { + iter.ReportError("ReadVal", "unexpected mismatched nesting") + return + } +} + +// WriteVal copy the go interface into underlying JSON, same as json.Marshal +func (stream *Stream) WriteVal(val interface{}) { + if nil == val { + stream.WriteNil() + return + } + cacheKey := reflect2.RTypeOf(val) + encoder := stream.cfg.getEncoderFromCache(cacheKey) + if encoder == nil { + typ := reflect2.TypeOf(val) + encoder = stream.cfg.EncoderOf(typ) + } + encoder.Encode(reflect2.PtrOf(val), stream) +} + +func (cfg *frozenConfig) DecoderOf(typ reflect2.Type) ValDecoder { + cacheKey := typ.RType() + decoder := cfg.getDecoderFromCache(cacheKey) + if decoder != nil { + return decoder + } + ctx := &ctx{ + frozenConfig: cfg, + prefix: "", + decoders: map[reflect2.Type]ValDecoder{}, + encoders: map[reflect2.Type]ValEncoder{}, + } + ptrType := typ.(*reflect2.UnsafePtrType) + decoder = decoderOfType(ctx, ptrType.Elem()) + cfg.addDecoderToCache(cacheKey, decoder) + return decoder +} + +func decoderOfType(ctx *ctx, typ reflect2.Type) ValDecoder { + decoder := getTypeDecoderFromExtension(ctx, typ) + if decoder != nil { + return decoder + } + decoder = createDecoderOfType(ctx, typ) + for _, extension := range extensions { + decoder = extension.DecorateDecoder(typ, decoder) + } + decoder = ctx.decoderExtension.DecorateDecoder(typ, decoder) + for _, extension := range ctx.extraExtensions { + decoder = extension.DecorateDecoder(typ, decoder) + } + return decoder +} + +func createDecoderOfType(ctx *ctx, typ reflect2.Type) ValDecoder { + decoder := ctx.decoders[typ] + if decoder != nil { + return decoder + } + placeholder := &placeholderDecoder{} + ctx.decoders[typ] = placeholder + decoder = _createDecoderOfType(ctx, typ) + placeholder.decoder = decoder + return decoder +} + +func _createDecoderOfType(ctx *ctx, typ reflect2.Type) ValDecoder { + decoder := createDecoderOfJsonRawMessage(ctx, typ) + if decoder != nil { + return decoder + } + decoder = createDecoderOfJsonNumber(ctx, typ) + if decoder != nil { + return decoder + } + decoder = createDecoderOfMarshaler(ctx, typ) + if decoder != nil { + return decoder + } + decoder = createDecoderOfAny(ctx, typ) + if decoder != nil { + return decoder + } + decoder = createDecoderOfNative(ctx, typ) + if decoder != nil { + return decoder + } + switch typ.Kind() { + case reflect.Interface: + ifaceType, isIFace := typ.(*reflect2.UnsafeIFaceType) + if isIFace { + return &ifaceDecoder{valType: ifaceType} + } + return &efaceDecoder{} + case reflect.Struct: + return decoderOfStruct(ctx, typ) + case reflect.Array: + return decoderOfArray(ctx, typ) + case reflect.Slice: + return decoderOfSlice(ctx, typ) + case reflect.Map: + return decoderOfMap(ctx, typ) + case reflect.Ptr: + return decoderOfOptional(ctx, typ) + default: + return &lazyErrorDecoder{err: fmt.Errorf("%s%s is unsupported type", ctx.prefix, typ.String())} + } +} + +func (cfg *frozenConfig) EncoderOf(typ reflect2.Type) ValEncoder { + cacheKey := typ.RType() + encoder := cfg.getEncoderFromCache(cacheKey) + if encoder != nil { + return encoder + } + ctx := &ctx{ + frozenConfig: cfg, + prefix: "", + decoders: map[reflect2.Type]ValDecoder{}, + encoders: map[reflect2.Type]ValEncoder{}, + } + encoder = encoderOfType(ctx, typ) + if typ.LikePtr() { + encoder = &onePtrEncoder{encoder} + } + cfg.addEncoderToCache(cacheKey, encoder) + return encoder +} + +type onePtrEncoder struct { + encoder ValEncoder +} + +func (encoder *onePtrEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return encoder.encoder.IsEmpty(unsafe.Pointer(&ptr)) +} + +func (encoder *onePtrEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + encoder.encoder.Encode(unsafe.Pointer(&ptr), stream) +} + +func encoderOfType(ctx *ctx, typ reflect2.Type) ValEncoder { + encoder := getTypeEncoderFromExtension(ctx, typ) + if encoder != nil { + return encoder + } + encoder = createEncoderOfType(ctx, typ) + for _, extension := range extensions { + encoder = extension.DecorateEncoder(typ, encoder) + } + encoder = ctx.encoderExtension.DecorateEncoder(typ, encoder) + for _, extension := range ctx.extraExtensions { + encoder = extension.DecorateEncoder(typ, encoder) + } + return encoder +} + +func createEncoderOfType(ctx *ctx, typ reflect2.Type) ValEncoder { + encoder := ctx.encoders[typ] + if encoder != nil { + return encoder + } + placeholder := &placeholderEncoder{} + ctx.encoders[typ] = placeholder + encoder = _createEncoderOfType(ctx, typ) + placeholder.encoder = encoder + return encoder +} +func _createEncoderOfType(ctx *ctx, typ reflect2.Type) ValEncoder { + encoder := createEncoderOfJsonRawMessage(ctx, typ) + if encoder != nil { + return encoder + } + encoder = createEncoderOfJsonNumber(ctx, typ) + if encoder != nil { + return encoder + } + encoder = createEncoderOfMarshaler(ctx, typ) + if encoder != nil { + return encoder + } + encoder = createEncoderOfAny(ctx, typ) + if encoder != nil { + return encoder + } + encoder = createEncoderOfNative(ctx, typ) + if encoder != nil { + return encoder + } + kind := typ.Kind() + switch kind { + case reflect.Interface: + return &dynamicEncoder{typ} + case reflect.Struct: + return encoderOfStruct(ctx, typ) + case reflect.Array: + return encoderOfArray(ctx, typ) + case reflect.Slice: + return encoderOfSlice(ctx, typ) + case reflect.Map: + return encoderOfMap(ctx, typ) + case reflect.Ptr: + return encoderOfOptional(ctx, typ) + default: + return &lazyErrorEncoder{err: fmt.Errorf("%s%s is unsupported type", ctx.prefix, typ.String())} + } +} + +type lazyErrorDecoder struct { + err error +} + +func (decoder *lazyErrorDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + if iter.WhatIsNext() != NilValue { + if iter.Error == nil { + iter.Error = decoder.err + } + } else { + iter.Skip() + } +} + +type lazyErrorEncoder struct { + err error +} + +func (encoder *lazyErrorEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + if ptr == nil { + stream.WriteNil() + } else if stream.Error == nil { + stream.Error = encoder.err + } +} + +func (encoder *lazyErrorEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return false +} + +type placeholderDecoder struct { + decoder ValDecoder +} + +func (decoder *placeholderDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + decoder.decoder.Decode(ptr, iter) +} + +type placeholderEncoder struct { + encoder ValEncoder +} + +func (encoder *placeholderEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + encoder.encoder.Encode(ptr, stream) +} + +func (encoder *placeholderEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return encoder.encoder.IsEmpty(ptr) +} diff --git a/vendor/github.com/json-iterator/go/reflect_array.go b/vendor/github.com/json-iterator/go/reflect_array.go new file mode 100644 index 0000000000000..13a0b7b0878cb --- /dev/null +++ b/vendor/github.com/json-iterator/go/reflect_array.go @@ -0,0 +1,104 @@ +package jsoniter + +import ( + "fmt" + "github.com/modern-go/reflect2" + "io" + "unsafe" +) + +func decoderOfArray(ctx *ctx, typ reflect2.Type) ValDecoder { + arrayType := typ.(*reflect2.UnsafeArrayType) + decoder := decoderOfType(ctx.append("[arrayElem]"), arrayType.Elem()) + return &arrayDecoder{arrayType, decoder} +} + +func encoderOfArray(ctx *ctx, typ reflect2.Type) ValEncoder { + arrayType := typ.(*reflect2.UnsafeArrayType) + if arrayType.Len() == 0 { + return emptyArrayEncoder{} + } + encoder := encoderOfType(ctx.append("[arrayElem]"), arrayType.Elem()) + return &arrayEncoder{arrayType, encoder} +} + +type emptyArrayEncoder struct{} + +func (encoder emptyArrayEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteEmptyArray() +} + +func (encoder emptyArrayEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return true +} + +type arrayEncoder struct { + arrayType *reflect2.UnsafeArrayType + elemEncoder ValEncoder +} + +func (encoder *arrayEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteArrayStart() + elemPtr := unsafe.Pointer(ptr) + encoder.elemEncoder.Encode(elemPtr, stream) + for i := 1; i < encoder.arrayType.Len(); i++ { + stream.WriteMore() + elemPtr = encoder.arrayType.UnsafeGetIndex(ptr, i) + encoder.elemEncoder.Encode(elemPtr, stream) + } + stream.WriteArrayEnd() + if stream.Error != nil && stream.Error != io.EOF { + stream.Error = fmt.Errorf("%v: %s", encoder.arrayType, stream.Error.Error()) + } +} + +func (encoder *arrayEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return false +} + +type arrayDecoder struct { + arrayType *reflect2.UnsafeArrayType + elemDecoder ValDecoder +} + +func (decoder *arrayDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + decoder.doDecode(ptr, iter) + if iter.Error != nil && iter.Error != io.EOF { + iter.Error = fmt.Errorf("%v: %s", decoder.arrayType, iter.Error.Error()) + } +} + +func (decoder *arrayDecoder) doDecode(ptr unsafe.Pointer, iter *Iterator) { + c := iter.nextToken() + arrayType := decoder.arrayType + if c == 'n' { + iter.skipThreeBytes('u', 'l', 'l') + return + } + if c != '[' { + iter.ReportError("decode array", "expect [ or n, but found "+string([]byte{c})) + return + } + c = iter.nextToken() + if c == ']' { + return + } + iter.unreadByte() + elemPtr := arrayType.UnsafeGetIndex(ptr, 0) + decoder.elemDecoder.Decode(elemPtr, iter) + length := 1 + for c = iter.nextToken(); c == ','; c = iter.nextToken() { + if length >= arrayType.Len() { + iter.Skip() + continue + } + idx := length + length += 1 + elemPtr = arrayType.UnsafeGetIndex(ptr, idx) + decoder.elemDecoder.Decode(elemPtr, iter) + } + if c != ']' { + iter.ReportError("decode array", "expect ], but found "+string([]byte{c})) + return + } +} diff --git a/vendor/github.com/json-iterator/go/reflect_dynamic.go b/vendor/github.com/json-iterator/go/reflect_dynamic.go new file mode 100644 index 0000000000000..8b6bc8b433286 --- /dev/null +++ b/vendor/github.com/json-iterator/go/reflect_dynamic.go @@ -0,0 +1,70 @@ +package jsoniter + +import ( + "github.com/modern-go/reflect2" + "reflect" + "unsafe" +) + +type dynamicEncoder struct { + valType reflect2.Type +} + +func (encoder *dynamicEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + obj := encoder.valType.UnsafeIndirect(ptr) + stream.WriteVal(obj) +} + +func (encoder *dynamicEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return encoder.valType.UnsafeIndirect(ptr) == nil +} + +type efaceDecoder struct { +} + +func (decoder *efaceDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + pObj := (*interface{})(ptr) + obj := *pObj + if obj == nil { + *pObj = iter.Read() + return + } + typ := reflect2.TypeOf(obj) + if typ.Kind() != reflect.Ptr { + *pObj = iter.Read() + return + } + ptrType := typ.(*reflect2.UnsafePtrType) + ptrElemType := ptrType.Elem() + if iter.WhatIsNext() == NilValue { + if ptrElemType.Kind() != reflect.Ptr { + iter.skipFourBytes('n', 'u', 'l', 'l') + *pObj = nil + return + } + } + if reflect2.IsNil(obj) { + obj := ptrElemType.New() + iter.ReadVal(obj) + *pObj = obj + return + } + iter.ReadVal(obj) +} + +type ifaceDecoder struct { + valType *reflect2.UnsafeIFaceType +} + +func (decoder *ifaceDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + if iter.ReadNil() { + decoder.valType.UnsafeSet(ptr, decoder.valType.UnsafeNew()) + return + } + obj := decoder.valType.UnsafeIndirect(ptr) + if reflect2.IsNil(obj) { + iter.ReportError("decode non empty interface", "can not unmarshal into nil") + return + } + iter.ReadVal(obj) +} diff --git a/vendor/github.com/json-iterator/go/reflect_extension.go b/vendor/github.com/json-iterator/go/reflect_extension.go new file mode 100644 index 0000000000000..80320cd64341f --- /dev/null +++ b/vendor/github.com/json-iterator/go/reflect_extension.go @@ -0,0 +1,483 @@ +package jsoniter + +import ( + "fmt" + "github.com/modern-go/reflect2" + "reflect" + "sort" + "strings" + "unicode" + "unsafe" +) + +var typeDecoders = map[string]ValDecoder{} +var fieldDecoders = map[string]ValDecoder{} +var typeEncoders = map[string]ValEncoder{} +var fieldEncoders = map[string]ValEncoder{} +var extensions = []Extension{} + +// StructDescriptor describe how should we encode/decode the struct +type StructDescriptor struct { + Type reflect2.Type + Fields []*Binding +} + +// GetField get one field from the descriptor by its name. +// Can not use map here to keep field orders. +func (structDescriptor *StructDescriptor) GetField(fieldName string) *Binding { + for _, binding := range structDescriptor.Fields { + if binding.Field.Name() == fieldName { + return binding + } + } + return nil +} + +// Binding describe how should we encode/decode the struct field +type Binding struct { + levels []int + Field reflect2.StructField + FromNames []string + ToNames []string + Encoder ValEncoder + Decoder ValDecoder +} + +// Extension the one for all SPI. Customize encoding/decoding by specifying alternate encoder/decoder. +// Can also rename fields by UpdateStructDescriptor. +type Extension interface { + UpdateStructDescriptor(structDescriptor *StructDescriptor) + CreateMapKeyDecoder(typ reflect2.Type) ValDecoder + CreateMapKeyEncoder(typ reflect2.Type) ValEncoder + CreateDecoder(typ reflect2.Type) ValDecoder + CreateEncoder(typ reflect2.Type) ValEncoder + DecorateDecoder(typ reflect2.Type, decoder ValDecoder) ValDecoder + DecorateEncoder(typ reflect2.Type, encoder ValEncoder) ValEncoder +} + +// DummyExtension embed this type get dummy implementation for all methods of Extension +type DummyExtension struct { +} + +// UpdateStructDescriptor No-op +func (extension *DummyExtension) UpdateStructDescriptor(structDescriptor *StructDescriptor) { +} + +// CreateMapKeyDecoder No-op +func (extension *DummyExtension) CreateMapKeyDecoder(typ reflect2.Type) ValDecoder { + return nil +} + +// CreateMapKeyEncoder No-op +func (extension *DummyExtension) CreateMapKeyEncoder(typ reflect2.Type) ValEncoder { + return nil +} + +// CreateDecoder No-op +func (extension *DummyExtension) CreateDecoder(typ reflect2.Type) ValDecoder { + return nil +} + +// CreateEncoder No-op +func (extension *DummyExtension) CreateEncoder(typ reflect2.Type) ValEncoder { + return nil +} + +// DecorateDecoder No-op +func (extension *DummyExtension) DecorateDecoder(typ reflect2.Type, decoder ValDecoder) ValDecoder { + return decoder +} + +// DecorateEncoder No-op +func (extension *DummyExtension) DecorateEncoder(typ reflect2.Type, encoder ValEncoder) ValEncoder { + return encoder +} + +type EncoderExtension map[reflect2.Type]ValEncoder + +// UpdateStructDescriptor No-op +func (extension EncoderExtension) UpdateStructDescriptor(structDescriptor *StructDescriptor) { +} + +// CreateDecoder No-op +func (extension EncoderExtension) CreateDecoder(typ reflect2.Type) ValDecoder { + return nil +} + +// CreateEncoder get encoder from map +func (extension EncoderExtension) CreateEncoder(typ reflect2.Type) ValEncoder { + return extension[typ] +} + +// CreateMapKeyDecoder No-op +func (extension EncoderExtension) CreateMapKeyDecoder(typ reflect2.Type) ValDecoder { + return nil +} + +// CreateMapKeyEncoder No-op +func (extension EncoderExtension) CreateMapKeyEncoder(typ reflect2.Type) ValEncoder { + return nil +} + +// DecorateDecoder No-op +func (extension EncoderExtension) DecorateDecoder(typ reflect2.Type, decoder ValDecoder) ValDecoder { + return decoder +} + +// DecorateEncoder No-op +func (extension EncoderExtension) DecorateEncoder(typ reflect2.Type, encoder ValEncoder) ValEncoder { + return encoder +} + +type DecoderExtension map[reflect2.Type]ValDecoder + +// UpdateStructDescriptor No-op +func (extension DecoderExtension) UpdateStructDescriptor(structDescriptor *StructDescriptor) { +} + +// CreateMapKeyDecoder No-op +func (extension DecoderExtension) CreateMapKeyDecoder(typ reflect2.Type) ValDecoder { + return nil +} + +// CreateMapKeyEncoder No-op +func (extension DecoderExtension) CreateMapKeyEncoder(typ reflect2.Type) ValEncoder { + return nil +} + +// CreateDecoder get decoder from map +func (extension DecoderExtension) CreateDecoder(typ reflect2.Type) ValDecoder { + return extension[typ] +} + +// CreateEncoder No-op +func (extension DecoderExtension) CreateEncoder(typ reflect2.Type) ValEncoder { + return nil +} + +// DecorateDecoder No-op +func (extension DecoderExtension) DecorateDecoder(typ reflect2.Type, decoder ValDecoder) ValDecoder { + return decoder +} + +// DecorateEncoder No-op +func (extension DecoderExtension) DecorateEncoder(typ reflect2.Type, encoder ValEncoder) ValEncoder { + return encoder +} + +type funcDecoder struct { + fun DecoderFunc +} + +func (decoder *funcDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + decoder.fun(ptr, iter) +} + +type funcEncoder struct { + fun EncoderFunc + isEmptyFunc func(ptr unsafe.Pointer) bool +} + +func (encoder *funcEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + encoder.fun(ptr, stream) +} + +func (encoder *funcEncoder) IsEmpty(ptr unsafe.Pointer) bool { + if encoder.isEmptyFunc == nil { + return false + } + return encoder.isEmptyFunc(ptr) +} + +// DecoderFunc the function form of TypeDecoder +type DecoderFunc func(ptr unsafe.Pointer, iter *Iterator) + +// EncoderFunc the function form of TypeEncoder +type EncoderFunc func(ptr unsafe.Pointer, stream *Stream) + +// RegisterTypeDecoderFunc register TypeDecoder for a type with function +func RegisterTypeDecoderFunc(typ string, fun DecoderFunc) { + typeDecoders[typ] = &funcDecoder{fun} +} + +// RegisterTypeDecoder register TypeDecoder for a typ +func RegisterTypeDecoder(typ string, decoder ValDecoder) { + typeDecoders[typ] = decoder +} + +// RegisterFieldDecoderFunc register TypeDecoder for a struct field with function +func RegisterFieldDecoderFunc(typ string, field string, fun DecoderFunc) { + RegisterFieldDecoder(typ, field, &funcDecoder{fun}) +} + +// RegisterFieldDecoder register TypeDecoder for a struct field +func RegisterFieldDecoder(typ string, field string, decoder ValDecoder) { + fieldDecoders[fmt.Sprintf("%s/%s", typ, field)] = decoder +} + +// RegisterTypeEncoderFunc register TypeEncoder for a type with encode/isEmpty function +func RegisterTypeEncoderFunc(typ string, fun EncoderFunc, isEmptyFunc func(unsafe.Pointer) bool) { + typeEncoders[typ] = &funcEncoder{fun, isEmptyFunc} +} + +// RegisterTypeEncoder register TypeEncoder for a type +func RegisterTypeEncoder(typ string, encoder ValEncoder) { + typeEncoders[typ] = encoder +} + +// RegisterFieldEncoderFunc register TypeEncoder for a struct field with encode/isEmpty function +func RegisterFieldEncoderFunc(typ string, field string, fun EncoderFunc, isEmptyFunc func(unsafe.Pointer) bool) { + RegisterFieldEncoder(typ, field, &funcEncoder{fun, isEmptyFunc}) +} + +// RegisterFieldEncoder register TypeEncoder for a struct field +func RegisterFieldEncoder(typ string, field string, encoder ValEncoder) { + fieldEncoders[fmt.Sprintf("%s/%s", typ, field)] = encoder +} + +// RegisterExtension register extension +func RegisterExtension(extension Extension) { + extensions = append(extensions, extension) +} + +func getTypeDecoderFromExtension(ctx *ctx, typ reflect2.Type) ValDecoder { + decoder := _getTypeDecoderFromExtension(ctx, typ) + if decoder != nil { + for _, extension := range extensions { + decoder = extension.DecorateDecoder(typ, decoder) + } + decoder = ctx.decoderExtension.DecorateDecoder(typ, decoder) + for _, extension := range ctx.extraExtensions { + decoder = extension.DecorateDecoder(typ, decoder) + } + } + return decoder +} +func _getTypeDecoderFromExtension(ctx *ctx, typ reflect2.Type) ValDecoder { + for _, extension := range extensions { + decoder := extension.CreateDecoder(typ) + if decoder != nil { + return decoder + } + } + decoder := ctx.decoderExtension.CreateDecoder(typ) + if decoder != nil { + return decoder + } + for _, extension := range ctx.extraExtensions { + decoder := extension.CreateDecoder(typ) + if decoder != nil { + return decoder + } + } + typeName := typ.String() + decoder = typeDecoders[typeName] + if decoder != nil { + return decoder + } + if typ.Kind() == reflect.Ptr { + ptrType := typ.(*reflect2.UnsafePtrType) + decoder := typeDecoders[ptrType.Elem().String()] + if decoder != nil { + return &OptionalDecoder{ptrType.Elem(), decoder} + } + } + return nil +} + +func getTypeEncoderFromExtension(ctx *ctx, typ reflect2.Type) ValEncoder { + encoder := _getTypeEncoderFromExtension(ctx, typ) + if encoder != nil { + for _, extension := range extensions { + encoder = extension.DecorateEncoder(typ, encoder) + } + encoder = ctx.encoderExtension.DecorateEncoder(typ, encoder) + for _, extension := range ctx.extraExtensions { + encoder = extension.DecorateEncoder(typ, encoder) + } + } + return encoder +} + +func _getTypeEncoderFromExtension(ctx *ctx, typ reflect2.Type) ValEncoder { + for _, extension := range extensions { + encoder := extension.CreateEncoder(typ) + if encoder != nil { + return encoder + } + } + encoder := ctx.encoderExtension.CreateEncoder(typ) + if encoder != nil { + return encoder + } + for _, extension := range ctx.extraExtensions { + encoder := extension.CreateEncoder(typ) + if encoder != nil { + return encoder + } + } + typeName := typ.String() + encoder = typeEncoders[typeName] + if encoder != nil { + return encoder + } + if typ.Kind() == reflect.Ptr { + typePtr := typ.(*reflect2.UnsafePtrType) + encoder := typeEncoders[typePtr.Elem().String()] + if encoder != nil { + return &OptionalEncoder{encoder} + } + } + return nil +} + +func describeStruct(ctx *ctx, typ reflect2.Type) *StructDescriptor { + structType := typ.(*reflect2.UnsafeStructType) + embeddedBindings := []*Binding{} + bindings := []*Binding{} + for i := 0; i < structType.NumField(); i++ { + field := structType.Field(i) + tag, hastag := field.Tag().Lookup(ctx.getTagKey()) + if ctx.onlyTaggedField && !hastag && !field.Anonymous() { + continue + } + if tag == "-" || field.Name() == "_" { + continue + } + tagParts := strings.Split(tag, ",") + if field.Anonymous() && (tag == "" || tagParts[0] == "") { + if field.Type().Kind() == reflect.Struct { + structDescriptor := describeStruct(ctx, field.Type()) + for _, binding := range structDescriptor.Fields { + binding.levels = append([]int{i}, binding.levels...) + omitempty := binding.Encoder.(*structFieldEncoder).omitempty + binding.Encoder = &structFieldEncoder{field, binding.Encoder, omitempty} + binding.Decoder = &structFieldDecoder{field, binding.Decoder} + embeddedBindings = append(embeddedBindings, binding) + } + continue + } else if field.Type().Kind() == reflect.Ptr { + ptrType := field.Type().(*reflect2.UnsafePtrType) + if ptrType.Elem().Kind() == reflect.Struct { + structDescriptor := describeStruct(ctx, ptrType.Elem()) + for _, binding := range structDescriptor.Fields { + binding.levels = append([]int{i}, binding.levels...) + omitempty := binding.Encoder.(*structFieldEncoder).omitempty + binding.Encoder = &dereferenceEncoder{binding.Encoder} + binding.Encoder = &structFieldEncoder{field, binding.Encoder, omitempty} + binding.Decoder = &dereferenceDecoder{ptrType.Elem(), binding.Decoder} + binding.Decoder = &structFieldDecoder{field, binding.Decoder} + embeddedBindings = append(embeddedBindings, binding) + } + continue + } + } + } + fieldNames := calcFieldNames(field.Name(), tagParts[0], tag) + fieldCacheKey := fmt.Sprintf("%s/%s", typ.String(), field.Name()) + decoder := fieldDecoders[fieldCacheKey] + if decoder == nil { + decoder = decoderOfType(ctx.append(field.Name()), field.Type()) + } + encoder := fieldEncoders[fieldCacheKey] + if encoder == nil { + encoder = encoderOfType(ctx.append(field.Name()), field.Type()) + } + binding := &Binding{ + Field: field, + FromNames: fieldNames, + ToNames: fieldNames, + Decoder: decoder, + Encoder: encoder, + } + binding.levels = []int{i} + bindings = append(bindings, binding) + } + return createStructDescriptor(ctx, typ, bindings, embeddedBindings) +} +func createStructDescriptor(ctx *ctx, typ reflect2.Type, bindings []*Binding, embeddedBindings []*Binding) *StructDescriptor { + structDescriptor := &StructDescriptor{ + Type: typ, + Fields: bindings, + } + for _, extension := range extensions { + extension.UpdateStructDescriptor(structDescriptor) + } + ctx.encoderExtension.UpdateStructDescriptor(structDescriptor) + ctx.decoderExtension.UpdateStructDescriptor(structDescriptor) + for _, extension := range ctx.extraExtensions { + extension.UpdateStructDescriptor(structDescriptor) + } + processTags(structDescriptor, ctx.frozenConfig) + // merge normal & embedded bindings & sort with original order + allBindings := sortableBindings(append(embeddedBindings, structDescriptor.Fields...)) + sort.Sort(allBindings) + structDescriptor.Fields = allBindings + return structDescriptor +} + +type sortableBindings []*Binding + +func (bindings sortableBindings) Len() int { + return len(bindings) +} + +func (bindings sortableBindings) Less(i, j int) bool { + left := bindings[i].levels + right := bindings[j].levels + k := 0 + for { + if left[k] < right[k] { + return true + } else if left[k] > right[k] { + return false + } + k++ + } +} + +func (bindings sortableBindings) Swap(i, j int) { + bindings[i], bindings[j] = bindings[j], bindings[i] +} + +func processTags(structDescriptor *StructDescriptor, cfg *frozenConfig) { + for _, binding := range structDescriptor.Fields { + shouldOmitEmpty := false + tagParts := strings.Split(binding.Field.Tag().Get(cfg.getTagKey()), ",") + for _, tagPart := range tagParts[1:] { + if tagPart == "omitempty" { + shouldOmitEmpty = true + } else if tagPart == "string" { + if binding.Field.Type().Kind() == reflect.String { + binding.Decoder = &stringModeStringDecoder{binding.Decoder, cfg} + binding.Encoder = &stringModeStringEncoder{binding.Encoder, cfg} + } else { + binding.Decoder = &stringModeNumberDecoder{binding.Decoder} + binding.Encoder = &stringModeNumberEncoder{binding.Encoder} + } + } + } + binding.Decoder = &structFieldDecoder{binding.Field, binding.Decoder} + binding.Encoder = &structFieldEncoder{binding.Field, binding.Encoder, shouldOmitEmpty} + } +} + +func calcFieldNames(originalFieldName string, tagProvidedFieldName string, wholeTag string) []string { + // ignore? + if wholeTag == "-" { + return []string{} + } + // rename? + var fieldNames []string + if tagProvidedFieldName == "" { + fieldNames = []string{originalFieldName} + } else { + fieldNames = []string{tagProvidedFieldName} + } + // private? + isNotExported := unicode.IsLower(rune(originalFieldName[0])) + if isNotExported { + fieldNames = []string{} + } + return fieldNames +} diff --git a/vendor/github.com/json-iterator/go/reflect_json_number.go b/vendor/github.com/json-iterator/go/reflect_json_number.go new file mode 100644 index 0000000000000..98d45c1ec2550 --- /dev/null +++ b/vendor/github.com/json-iterator/go/reflect_json_number.go @@ -0,0 +1,112 @@ +package jsoniter + +import ( + "encoding/json" + "github.com/modern-go/reflect2" + "strconv" + "unsafe" +) + +type Number string + +// String returns the literal text of the number. +func (n Number) String() string { return string(n) } + +// Float64 returns the number as a float64. +func (n Number) Float64() (float64, error) { + return strconv.ParseFloat(string(n), 64) +} + +// Int64 returns the number as an int64. +func (n Number) Int64() (int64, error) { + return strconv.ParseInt(string(n), 10, 64) +} + +func CastJsonNumber(val interface{}) (string, bool) { + switch typedVal := val.(type) { + case json.Number: + return string(typedVal), true + case Number: + return string(typedVal), true + } + return "", false +} + +var jsonNumberType = reflect2.TypeOfPtr((*json.Number)(nil)).Elem() +var jsoniterNumberType = reflect2.TypeOfPtr((*Number)(nil)).Elem() + +func createDecoderOfJsonNumber(ctx *ctx, typ reflect2.Type) ValDecoder { + if typ.AssignableTo(jsonNumberType) { + return &jsonNumberCodec{} + } + if typ.AssignableTo(jsoniterNumberType) { + return &jsoniterNumberCodec{} + } + return nil +} + +func createEncoderOfJsonNumber(ctx *ctx, typ reflect2.Type) ValEncoder { + if typ.AssignableTo(jsonNumberType) { + return &jsonNumberCodec{} + } + if typ.AssignableTo(jsoniterNumberType) { + return &jsoniterNumberCodec{} + } + return nil +} + +type jsonNumberCodec struct { +} + +func (codec *jsonNumberCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { + switch iter.WhatIsNext() { + case StringValue: + *((*json.Number)(ptr)) = json.Number(iter.ReadString()) + case NilValue: + iter.skipFourBytes('n', 'u', 'l', 'l') + *((*json.Number)(ptr)) = "" + default: + *((*json.Number)(ptr)) = json.Number([]byte(iter.readNumberAsString())) + } +} + +func (codec *jsonNumberCodec) Encode(ptr unsafe.Pointer, stream *Stream) { + number := *((*json.Number)(ptr)) + if len(number) == 0 { + stream.writeByte('0') + } else { + stream.WriteRaw(string(number)) + } +} + +func (codec *jsonNumberCodec) IsEmpty(ptr unsafe.Pointer) bool { + return len(*((*json.Number)(ptr))) == 0 +} + +type jsoniterNumberCodec struct { +} + +func (codec *jsoniterNumberCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { + switch iter.WhatIsNext() { + case StringValue: + *((*Number)(ptr)) = Number(iter.ReadString()) + case NilValue: + iter.skipFourBytes('n', 'u', 'l', 'l') + *((*Number)(ptr)) = "" + default: + *((*Number)(ptr)) = Number([]byte(iter.readNumberAsString())) + } +} + +func (codec *jsoniterNumberCodec) Encode(ptr unsafe.Pointer, stream *Stream) { + number := *((*Number)(ptr)) + if len(number) == 0 { + stream.writeByte('0') + } else { + stream.WriteRaw(string(number)) + } +} + +func (codec *jsoniterNumberCodec) IsEmpty(ptr unsafe.Pointer) bool { + return len(*((*Number)(ptr))) == 0 +} diff --git a/vendor/github.com/json-iterator/go/reflect_json_raw_message.go b/vendor/github.com/json-iterator/go/reflect_json_raw_message.go new file mode 100644 index 0000000000000..f2619936c88fd --- /dev/null +++ b/vendor/github.com/json-iterator/go/reflect_json_raw_message.go @@ -0,0 +1,60 @@ +package jsoniter + +import ( + "encoding/json" + "github.com/modern-go/reflect2" + "unsafe" +) + +var jsonRawMessageType = reflect2.TypeOfPtr((*json.RawMessage)(nil)).Elem() +var jsoniterRawMessageType = reflect2.TypeOfPtr((*RawMessage)(nil)).Elem() + +func createEncoderOfJsonRawMessage(ctx *ctx, typ reflect2.Type) ValEncoder { + if typ == jsonRawMessageType { + return &jsonRawMessageCodec{} + } + if typ == jsoniterRawMessageType { + return &jsoniterRawMessageCodec{} + } + return nil +} + +func createDecoderOfJsonRawMessage(ctx *ctx, typ reflect2.Type) ValDecoder { + if typ == jsonRawMessageType { + return &jsonRawMessageCodec{} + } + if typ == jsoniterRawMessageType { + return &jsoniterRawMessageCodec{} + } + return nil +} + +type jsonRawMessageCodec struct { +} + +func (codec *jsonRawMessageCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { + *((*json.RawMessage)(ptr)) = json.RawMessage(iter.SkipAndReturnBytes()) +} + +func (codec *jsonRawMessageCodec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteRaw(string(*((*json.RawMessage)(ptr)))) +} + +func (codec *jsonRawMessageCodec) IsEmpty(ptr unsafe.Pointer) bool { + return len(*((*json.RawMessage)(ptr))) == 0 +} + +type jsoniterRawMessageCodec struct { +} + +func (codec *jsoniterRawMessageCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { + *((*RawMessage)(ptr)) = RawMessage(iter.SkipAndReturnBytes()) +} + +func (codec *jsoniterRawMessageCodec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteRaw(string(*((*RawMessage)(ptr)))) +} + +func (codec *jsoniterRawMessageCodec) IsEmpty(ptr unsafe.Pointer) bool { + return len(*((*RawMessage)(ptr))) == 0 +} diff --git a/vendor/github.com/json-iterator/go/reflect_map.go b/vendor/github.com/json-iterator/go/reflect_map.go new file mode 100644 index 0000000000000..9e2b623fe8d61 --- /dev/null +++ b/vendor/github.com/json-iterator/go/reflect_map.go @@ -0,0 +1,346 @@ +package jsoniter + +import ( + "fmt" + "github.com/modern-go/reflect2" + "io" + "reflect" + "sort" + "unsafe" +) + +func decoderOfMap(ctx *ctx, typ reflect2.Type) ValDecoder { + mapType := typ.(*reflect2.UnsafeMapType) + keyDecoder := decoderOfMapKey(ctx.append("[mapKey]"), mapType.Key()) + elemDecoder := decoderOfType(ctx.append("[mapElem]"), mapType.Elem()) + return &mapDecoder{ + mapType: mapType, + keyType: mapType.Key(), + elemType: mapType.Elem(), + keyDecoder: keyDecoder, + elemDecoder: elemDecoder, + } +} + +func encoderOfMap(ctx *ctx, typ reflect2.Type) ValEncoder { + mapType := typ.(*reflect2.UnsafeMapType) + if ctx.sortMapKeys { + return &sortKeysMapEncoder{ + mapType: mapType, + keyEncoder: encoderOfMapKey(ctx.append("[mapKey]"), mapType.Key()), + elemEncoder: encoderOfType(ctx.append("[mapElem]"), mapType.Elem()), + } + } + return &mapEncoder{ + mapType: mapType, + keyEncoder: encoderOfMapKey(ctx.append("[mapKey]"), mapType.Key()), + elemEncoder: encoderOfType(ctx.append("[mapElem]"), mapType.Elem()), + } +} + +func decoderOfMapKey(ctx *ctx, typ reflect2.Type) ValDecoder { + decoder := ctx.decoderExtension.CreateMapKeyDecoder(typ) + if decoder != nil { + return decoder + } + for _, extension := range ctx.extraExtensions { + decoder := extension.CreateMapKeyDecoder(typ) + if decoder != nil { + return decoder + } + } + switch typ.Kind() { + case reflect.String: + return decoderOfType(ctx, reflect2.DefaultTypeOfKind(reflect.String)) + case reflect.Bool, + reflect.Uint8, reflect.Int8, + reflect.Uint16, reflect.Int16, + reflect.Uint32, reflect.Int32, + reflect.Uint64, reflect.Int64, + reflect.Uint, reflect.Int, + reflect.Float32, reflect.Float64, + reflect.Uintptr: + typ = reflect2.DefaultTypeOfKind(typ.Kind()) + return &numericMapKeyDecoder{decoderOfType(ctx, typ)} + default: + ptrType := reflect2.PtrTo(typ) + if ptrType.Implements(unmarshalerType) { + return &referenceDecoder{ + &unmarshalerDecoder{ + valType: ptrType, + }, + } + } + if typ.Implements(unmarshalerType) { + return &unmarshalerDecoder{ + valType: typ, + } + } + if ptrType.Implements(textUnmarshalerType) { + return &referenceDecoder{ + &textUnmarshalerDecoder{ + valType: ptrType, + }, + } + } + if typ.Implements(textUnmarshalerType) { + return &textUnmarshalerDecoder{ + valType: typ, + } + } + return &lazyErrorDecoder{err: fmt.Errorf("unsupported map key type: %v", typ)} + } +} + +func encoderOfMapKey(ctx *ctx, typ reflect2.Type) ValEncoder { + encoder := ctx.encoderExtension.CreateMapKeyEncoder(typ) + if encoder != nil { + return encoder + } + for _, extension := range ctx.extraExtensions { + encoder := extension.CreateMapKeyEncoder(typ) + if encoder != nil { + return encoder + } + } + switch typ.Kind() { + case reflect.String: + return encoderOfType(ctx, reflect2.DefaultTypeOfKind(reflect.String)) + case reflect.Bool, + reflect.Uint8, reflect.Int8, + reflect.Uint16, reflect.Int16, + reflect.Uint32, reflect.Int32, + reflect.Uint64, reflect.Int64, + reflect.Uint, reflect.Int, + reflect.Float32, reflect.Float64, + reflect.Uintptr: + typ = reflect2.DefaultTypeOfKind(typ.Kind()) + return &numericMapKeyEncoder{encoderOfType(ctx, typ)} + default: + if typ == textMarshalerType { + return &directTextMarshalerEncoder{ + stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")), + } + } + if typ.Implements(textMarshalerType) { + return &textMarshalerEncoder{ + valType: typ, + stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")), + } + } + if typ.Kind() == reflect.Interface { + return &dynamicMapKeyEncoder{ctx, typ} + } + return &lazyErrorEncoder{err: fmt.Errorf("unsupported map key type: %v", typ)} + } +} + +type mapDecoder struct { + mapType *reflect2.UnsafeMapType + keyType reflect2.Type + elemType reflect2.Type + keyDecoder ValDecoder + elemDecoder ValDecoder +} + +func (decoder *mapDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + mapType := decoder.mapType + c := iter.nextToken() + if c == 'n' { + iter.skipThreeBytes('u', 'l', 'l') + *(*unsafe.Pointer)(ptr) = nil + mapType.UnsafeSet(ptr, mapType.UnsafeNew()) + return + } + if mapType.UnsafeIsNil(ptr) { + mapType.UnsafeSet(ptr, mapType.UnsafeMakeMap(0)) + } + if c != '{' { + iter.ReportError("ReadMapCB", `expect { or n, but found `+string([]byte{c})) + return + } + c = iter.nextToken() + if c == '}' { + return + } + if c != '"' { + iter.ReportError("ReadMapCB", `expect " after }, but found `+string([]byte{c})) + return + } + iter.unreadByte() + key := decoder.keyType.UnsafeNew() + decoder.keyDecoder.Decode(key, iter) + c = iter.nextToken() + if c != ':' { + iter.ReportError("ReadMapCB", "expect : after object field, but found "+string([]byte{c})) + return + } + elem := decoder.elemType.UnsafeNew() + decoder.elemDecoder.Decode(elem, iter) + decoder.mapType.UnsafeSetIndex(ptr, key, elem) + for c = iter.nextToken(); c == ','; c = iter.nextToken() { + key := decoder.keyType.UnsafeNew() + decoder.keyDecoder.Decode(key, iter) + c = iter.nextToken() + if c != ':' { + iter.ReportError("ReadMapCB", "expect : after object field, but found "+string([]byte{c})) + return + } + elem := decoder.elemType.UnsafeNew() + decoder.elemDecoder.Decode(elem, iter) + decoder.mapType.UnsafeSetIndex(ptr, key, elem) + } + if c != '}' { + iter.ReportError("ReadMapCB", `expect }, but found `+string([]byte{c})) + } +} + +type numericMapKeyDecoder struct { + decoder ValDecoder +} + +func (decoder *numericMapKeyDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + c := iter.nextToken() + if c != '"' { + iter.ReportError("ReadMapCB", `expect ", but found `+string([]byte{c})) + return + } + decoder.decoder.Decode(ptr, iter) + c = iter.nextToken() + if c != '"' { + iter.ReportError("ReadMapCB", `expect ", but found `+string([]byte{c})) + return + } +} + +type numericMapKeyEncoder struct { + encoder ValEncoder +} + +func (encoder *numericMapKeyEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.writeByte('"') + encoder.encoder.Encode(ptr, stream) + stream.writeByte('"') +} + +func (encoder *numericMapKeyEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return false +} + +type dynamicMapKeyEncoder struct { + ctx *ctx + valType reflect2.Type +} + +func (encoder *dynamicMapKeyEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + obj := encoder.valType.UnsafeIndirect(ptr) + encoderOfMapKey(encoder.ctx, reflect2.TypeOf(obj)).Encode(reflect2.PtrOf(obj), stream) +} + +func (encoder *dynamicMapKeyEncoder) IsEmpty(ptr unsafe.Pointer) bool { + obj := encoder.valType.UnsafeIndirect(ptr) + return encoderOfMapKey(encoder.ctx, reflect2.TypeOf(obj)).IsEmpty(reflect2.PtrOf(obj)) +} + +type mapEncoder struct { + mapType *reflect2.UnsafeMapType + keyEncoder ValEncoder + elemEncoder ValEncoder +} + +func (encoder *mapEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + if *(*unsafe.Pointer)(ptr) == nil { + stream.WriteNil() + return + } + stream.WriteObjectStart() + iter := encoder.mapType.UnsafeIterate(ptr) + for i := 0; iter.HasNext(); i++ { + if i != 0 { + stream.WriteMore() + } + key, elem := iter.UnsafeNext() + encoder.keyEncoder.Encode(key, stream) + if stream.indention > 0 { + stream.writeTwoBytes(byte(':'), byte(' ')) + } else { + stream.writeByte(':') + } + encoder.elemEncoder.Encode(elem, stream) + } + stream.WriteObjectEnd() +} + +func (encoder *mapEncoder) IsEmpty(ptr unsafe.Pointer) bool { + iter := encoder.mapType.UnsafeIterate(ptr) + return !iter.HasNext() +} + +type sortKeysMapEncoder struct { + mapType *reflect2.UnsafeMapType + keyEncoder ValEncoder + elemEncoder ValEncoder +} + +func (encoder *sortKeysMapEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + if *(*unsafe.Pointer)(ptr) == nil { + stream.WriteNil() + return + } + stream.WriteObjectStart() + mapIter := encoder.mapType.UnsafeIterate(ptr) + subStream := stream.cfg.BorrowStream(nil) + subStream.Attachment = stream.Attachment + subIter := stream.cfg.BorrowIterator(nil) + keyValues := encodedKeyValues{} + for mapIter.HasNext() { + key, elem := mapIter.UnsafeNext() + subStreamIndex := subStream.Buffered() + encoder.keyEncoder.Encode(key, subStream) + if subStream.Error != nil && subStream.Error != io.EOF && stream.Error == nil { + stream.Error = subStream.Error + } + encodedKey := subStream.Buffer()[subStreamIndex:] + subIter.ResetBytes(encodedKey) + decodedKey := subIter.ReadString() + if stream.indention > 0 { + subStream.writeTwoBytes(byte(':'), byte(' ')) + } else { + subStream.writeByte(':') + } + encoder.elemEncoder.Encode(elem, subStream) + keyValues = append(keyValues, encodedKV{ + key: decodedKey, + keyValue: subStream.Buffer()[subStreamIndex:], + }) + } + sort.Sort(keyValues) + for i, keyValue := range keyValues { + if i != 0 { + stream.WriteMore() + } + stream.Write(keyValue.keyValue) + } + if subStream.Error != nil && stream.Error == nil { + stream.Error = subStream.Error + } + stream.WriteObjectEnd() + stream.cfg.ReturnStream(subStream) + stream.cfg.ReturnIterator(subIter) +} + +func (encoder *sortKeysMapEncoder) IsEmpty(ptr unsafe.Pointer) bool { + iter := encoder.mapType.UnsafeIterate(ptr) + return !iter.HasNext() +} + +type encodedKeyValues []encodedKV + +type encodedKV struct { + key string + keyValue []byte +} + +func (sv encodedKeyValues) Len() int { return len(sv) } +func (sv encodedKeyValues) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[i] } +func (sv encodedKeyValues) Less(i, j int) bool { return sv[i].key < sv[j].key } diff --git a/vendor/github.com/json-iterator/go/reflect_marshaler.go b/vendor/github.com/json-iterator/go/reflect_marshaler.go new file mode 100644 index 0000000000000..3e21f3756717a --- /dev/null +++ b/vendor/github.com/json-iterator/go/reflect_marshaler.go @@ -0,0 +1,225 @@ +package jsoniter + +import ( + "encoding" + "encoding/json" + "unsafe" + + "github.com/modern-go/reflect2" +) + +var marshalerType = reflect2.TypeOfPtr((*json.Marshaler)(nil)).Elem() +var unmarshalerType = reflect2.TypeOfPtr((*json.Unmarshaler)(nil)).Elem() +var textMarshalerType = reflect2.TypeOfPtr((*encoding.TextMarshaler)(nil)).Elem() +var textUnmarshalerType = reflect2.TypeOfPtr((*encoding.TextUnmarshaler)(nil)).Elem() + +func createDecoderOfMarshaler(ctx *ctx, typ reflect2.Type) ValDecoder { + ptrType := reflect2.PtrTo(typ) + if ptrType.Implements(unmarshalerType) { + return &referenceDecoder{ + &unmarshalerDecoder{ptrType}, + } + } + if ptrType.Implements(textUnmarshalerType) { + return &referenceDecoder{ + &textUnmarshalerDecoder{ptrType}, + } + } + return nil +} + +func createEncoderOfMarshaler(ctx *ctx, typ reflect2.Type) ValEncoder { + if typ == marshalerType { + checkIsEmpty := createCheckIsEmpty(ctx, typ) + var encoder ValEncoder = &directMarshalerEncoder{ + checkIsEmpty: checkIsEmpty, + } + return encoder + } + if typ.Implements(marshalerType) { + checkIsEmpty := createCheckIsEmpty(ctx, typ) + var encoder ValEncoder = &marshalerEncoder{ + valType: typ, + checkIsEmpty: checkIsEmpty, + } + return encoder + } + ptrType := reflect2.PtrTo(typ) + if ctx.prefix != "" && ptrType.Implements(marshalerType) { + checkIsEmpty := createCheckIsEmpty(ctx, ptrType) + var encoder ValEncoder = &marshalerEncoder{ + valType: ptrType, + checkIsEmpty: checkIsEmpty, + } + return &referenceEncoder{encoder} + } + if typ == textMarshalerType { + checkIsEmpty := createCheckIsEmpty(ctx, typ) + var encoder ValEncoder = &directTextMarshalerEncoder{ + checkIsEmpty: checkIsEmpty, + stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")), + } + return encoder + } + if typ.Implements(textMarshalerType) { + checkIsEmpty := createCheckIsEmpty(ctx, typ) + var encoder ValEncoder = &textMarshalerEncoder{ + valType: typ, + stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")), + checkIsEmpty: checkIsEmpty, + } + return encoder + } + // if prefix is empty, the type is the root type + if ctx.prefix != "" && ptrType.Implements(textMarshalerType) { + checkIsEmpty := createCheckIsEmpty(ctx, ptrType) + var encoder ValEncoder = &textMarshalerEncoder{ + valType: ptrType, + stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")), + checkIsEmpty: checkIsEmpty, + } + return &referenceEncoder{encoder} + } + return nil +} + +type marshalerEncoder struct { + checkIsEmpty checkIsEmpty + valType reflect2.Type +} + +func (encoder *marshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + obj := encoder.valType.UnsafeIndirect(ptr) + if encoder.valType.IsNullable() && reflect2.IsNil(obj) { + stream.WriteNil() + return + } + marshaler := obj.(json.Marshaler) + bytes, err := marshaler.MarshalJSON() + if err != nil { + stream.Error = err + } else { + // html escape was already done by jsoniter + // but the extra '\n' should be trimed + l := len(bytes) + if l > 0 && bytes[l-1] == '\n' { + bytes = bytes[:l-1] + } + stream.Write(bytes) + } +} + +func (encoder *marshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return encoder.checkIsEmpty.IsEmpty(ptr) +} + +type directMarshalerEncoder struct { + checkIsEmpty checkIsEmpty +} + +func (encoder *directMarshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + marshaler := *(*json.Marshaler)(ptr) + if marshaler == nil { + stream.WriteNil() + return + } + bytes, err := marshaler.MarshalJSON() + if err != nil { + stream.Error = err + } else { + stream.Write(bytes) + } +} + +func (encoder *directMarshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return encoder.checkIsEmpty.IsEmpty(ptr) +} + +type textMarshalerEncoder struct { + valType reflect2.Type + stringEncoder ValEncoder + checkIsEmpty checkIsEmpty +} + +func (encoder *textMarshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + obj := encoder.valType.UnsafeIndirect(ptr) + if encoder.valType.IsNullable() && reflect2.IsNil(obj) { + stream.WriteNil() + return + } + marshaler := (obj).(encoding.TextMarshaler) + bytes, err := marshaler.MarshalText() + if err != nil { + stream.Error = err + } else { + str := string(bytes) + encoder.stringEncoder.Encode(unsafe.Pointer(&str), stream) + } +} + +func (encoder *textMarshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return encoder.checkIsEmpty.IsEmpty(ptr) +} + +type directTextMarshalerEncoder struct { + stringEncoder ValEncoder + checkIsEmpty checkIsEmpty +} + +func (encoder *directTextMarshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + marshaler := *(*encoding.TextMarshaler)(ptr) + if marshaler == nil { + stream.WriteNil() + return + } + bytes, err := marshaler.MarshalText() + if err != nil { + stream.Error = err + } else { + str := string(bytes) + encoder.stringEncoder.Encode(unsafe.Pointer(&str), stream) + } +} + +func (encoder *directTextMarshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return encoder.checkIsEmpty.IsEmpty(ptr) +} + +type unmarshalerDecoder struct { + valType reflect2.Type +} + +func (decoder *unmarshalerDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + valType := decoder.valType + obj := valType.UnsafeIndirect(ptr) + unmarshaler := obj.(json.Unmarshaler) + iter.nextToken() + iter.unreadByte() // skip spaces + bytes := iter.SkipAndReturnBytes() + err := unmarshaler.UnmarshalJSON(bytes) + if err != nil { + iter.ReportError("unmarshalerDecoder", err.Error()) + } +} + +type textUnmarshalerDecoder struct { + valType reflect2.Type +} + +func (decoder *textUnmarshalerDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + valType := decoder.valType + obj := valType.UnsafeIndirect(ptr) + if reflect2.IsNil(obj) { + ptrType := valType.(*reflect2.UnsafePtrType) + elemType := ptrType.Elem() + elem := elemType.UnsafeNew() + ptrType.UnsafeSet(ptr, unsafe.Pointer(&elem)) + obj = valType.UnsafeIndirect(ptr) + } + unmarshaler := (obj).(encoding.TextUnmarshaler) + str := iter.ReadString() + err := unmarshaler.UnmarshalText([]byte(str)) + if err != nil { + iter.ReportError("textUnmarshalerDecoder", err.Error()) + } +} diff --git a/vendor/github.com/json-iterator/go/reflect_native.go b/vendor/github.com/json-iterator/go/reflect_native.go new file mode 100644 index 0000000000000..f88722d14d198 --- /dev/null +++ b/vendor/github.com/json-iterator/go/reflect_native.go @@ -0,0 +1,453 @@ +package jsoniter + +import ( + "encoding/base64" + "reflect" + "strconv" + "unsafe" + + "github.com/modern-go/reflect2" +) + +const ptrSize = 32 << uintptr(^uintptr(0)>>63) + +func createEncoderOfNative(ctx *ctx, typ reflect2.Type) ValEncoder { + if typ.Kind() == reflect.Slice && typ.(reflect2.SliceType).Elem().Kind() == reflect.Uint8 { + sliceDecoder := decoderOfSlice(ctx, typ) + return &base64Codec{sliceDecoder: sliceDecoder} + } + typeName := typ.String() + kind := typ.Kind() + switch kind { + case reflect.String: + if typeName != "string" { + return encoderOfType(ctx, reflect2.TypeOfPtr((*string)(nil)).Elem()) + } + return &stringCodec{} + case reflect.Int: + if typeName != "int" { + return encoderOfType(ctx, reflect2.TypeOfPtr((*int)(nil)).Elem()) + } + if strconv.IntSize == 32 { + return &int32Codec{} + } + return &int64Codec{} + case reflect.Int8: + if typeName != "int8" { + return encoderOfType(ctx, reflect2.TypeOfPtr((*int8)(nil)).Elem()) + } + return &int8Codec{} + case reflect.Int16: + if typeName != "int16" { + return encoderOfType(ctx, reflect2.TypeOfPtr((*int16)(nil)).Elem()) + } + return &int16Codec{} + case reflect.Int32: + if typeName != "int32" { + return encoderOfType(ctx, reflect2.TypeOfPtr((*int32)(nil)).Elem()) + } + return &int32Codec{} + case reflect.Int64: + if typeName != "int64" { + return encoderOfType(ctx, reflect2.TypeOfPtr((*int64)(nil)).Elem()) + } + return &int64Codec{} + case reflect.Uint: + if typeName != "uint" { + return encoderOfType(ctx, reflect2.TypeOfPtr((*uint)(nil)).Elem()) + } + if strconv.IntSize == 32 { + return &uint32Codec{} + } + return &uint64Codec{} + case reflect.Uint8: + if typeName != "uint8" { + return encoderOfType(ctx, reflect2.TypeOfPtr((*uint8)(nil)).Elem()) + } + return &uint8Codec{} + case reflect.Uint16: + if typeName != "uint16" { + return encoderOfType(ctx, reflect2.TypeOfPtr((*uint16)(nil)).Elem()) + } + return &uint16Codec{} + case reflect.Uint32: + if typeName != "uint32" { + return encoderOfType(ctx, reflect2.TypeOfPtr((*uint32)(nil)).Elem()) + } + return &uint32Codec{} + case reflect.Uintptr: + if typeName != "uintptr" { + return encoderOfType(ctx, reflect2.TypeOfPtr((*uintptr)(nil)).Elem()) + } + if ptrSize == 32 { + return &uint32Codec{} + } + return &uint64Codec{} + case reflect.Uint64: + if typeName != "uint64" { + return encoderOfType(ctx, reflect2.TypeOfPtr((*uint64)(nil)).Elem()) + } + return &uint64Codec{} + case reflect.Float32: + if typeName != "float32" { + return encoderOfType(ctx, reflect2.TypeOfPtr((*float32)(nil)).Elem()) + } + return &float32Codec{} + case reflect.Float64: + if typeName != "float64" { + return encoderOfType(ctx, reflect2.TypeOfPtr((*float64)(nil)).Elem()) + } + return &float64Codec{} + case reflect.Bool: + if typeName != "bool" { + return encoderOfType(ctx, reflect2.TypeOfPtr((*bool)(nil)).Elem()) + } + return &boolCodec{} + } + return nil +} + +func createDecoderOfNative(ctx *ctx, typ reflect2.Type) ValDecoder { + if typ.Kind() == reflect.Slice && typ.(reflect2.SliceType).Elem().Kind() == reflect.Uint8 { + sliceDecoder := decoderOfSlice(ctx, typ) + return &base64Codec{sliceDecoder: sliceDecoder} + } + typeName := typ.String() + switch typ.Kind() { + case reflect.String: + if typeName != "string" { + return decoderOfType(ctx, reflect2.TypeOfPtr((*string)(nil)).Elem()) + } + return &stringCodec{} + case reflect.Int: + if typeName != "int" { + return decoderOfType(ctx, reflect2.TypeOfPtr((*int)(nil)).Elem()) + } + if strconv.IntSize == 32 { + return &int32Codec{} + } + return &int64Codec{} + case reflect.Int8: + if typeName != "int8" { + return decoderOfType(ctx, reflect2.TypeOfPtr((*int8)(nil)).Elem()) + } + return &int8Codec{} + case reflect.Int16: + if typeName != "int16" { + return decoderOfType(ctx, reflect2.TypeOfPtr((*int16)(nil)).Elem()) + } + return &int16Codec{} + case reflect.Int32: + if typeName != "int32" { + return decoderOfType(ctx, reflect2.TypeOfPtr((*int32)(nil)).Elem()) + } + return &int32Codec{} + case reflect.Int64: + if typeName != "int64" { + return decoderOfType(ctx, reflect2.TypeOfPtr((*int64)(nil)).Elem()) + } + return &int64Codec{} + case reflect.Uint: + if typeName != "uint" { + return decoderOfType(ctx, reflect2.TypeOfPtr((*uint)(nil)).Elem()) + } + if strconv.IntSize == 32 { + return &uint32Codec{} + } + return &uint64Codec{} + case reflect.Uint8: + if typeName != "uint8" { + return decoderOfType(ctx, reflect2.TypeOfPtr((*uint8)(nil)).Elem()) + } + return &uint8Codec{} + case reflect.Uint16: + if typeName != "uint16" { + return decoderOfType(ctx, reflect2.TypeOfPtr((*uint16)(nil)).Elem()) + } + return &uint16Codec{} + case reflect.Uint32: + if typeName != "uint32" { + return decoderOfType(ctx, reflect2.TypeOfPtr((*uint32)(nil)).Elem()) + } + return &uint32Codec{} + case reflect.Uintptr: + if typeName != "uintptr" { + return decoderOfType(ctx, reflect2.TypeOfPtr((*uintptr)(nil)).Elem()) + } + if ptrSize == 32 { + return &uint32Codec{} + } + return &uint64Codec{} + case reflect.Uint64: + if typeName != "uint64" { + return decoderOfType(ctx, reflect2.TypeOfPtr((*uint64)(nil)).Elem()) + } + return &uint64Codec{} + case reflect.Float32: + if typeName != "float32" { + return decoderOfType(ctx, reflect2.TypeOfPtr((*float32)(nil)).Elem()) + } + return &float32Codec{} + case reflect.Float64: + if typeName != "float64" { + return decoderOfType(ctx, reflect2.TypeOfPtr((*float64)(nil)).Elem()) + } + return &float64Codec{} + case reflect.Bool: + if typeName != "bool" { + return decoderOfType(ctx, reflect2.TypeOfPtr((*bool)(nil)).Elem()) + } + return &boolCodec{} + } + return nil +} + +type stringCodec struct { +} + +func (codec *stringCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { + *((*string)(ptr)) = iter.ReadString() +} + +func (codec *stringCodec) Encode(ptr unsafe.Pointer, stream *Stream) { + str := *((*string)(ptr)) + stream.WriteString(str) +} + +func (codec *stringCodec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*string)(ptr)) == "" +} + +type int8Codec struct { +} + +func (codec *int8Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.ReadNil() { + *((*int8)(ptr)) = iter.ReadInt8() + } +} + +func (codec *int8Codec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteInt8(*((*int8)(ptr))) +} + +func (codec *int8Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*int8)(ptr)) == 0 +} + +type int16Codec struct { +} + +func (codec *int16Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.ReadNil() { + *((*int16)(ptr)) = iter.ReadInt16() + } +} + +func (codec *int16Codec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteInt16(*((*int16)(ptr))) +} + +func (codec *int16Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*int16)(ptr)) == 0 +} + +type int32Codec struct { +} + +func (codec *int32Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.ReadNil() { + *((*int32)(ptr)) = iter.ReadInt32() + } +} + +func (codec *int32Codec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteInt32(*((*int32)(ptr))) +} + +func (codec *int32Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*int32)(ptr)) == 0 +} + +type int64Codec struct { +} + +func (codec *int64Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.ReadNil() { + *((*int64)(ptr)) = iter.ReadInt64() + } +} + +func (codec *int64Codec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteInt64(*((*int64)(ptr))) +} + +func (codec *int64Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*int64)(ptr)) == 0 +} + +type uint8Codec struct { +} + +func (codec *uint8Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.ReadNil() { + *((*uint8)(ptr)) = iter.ReadUint8() + } +} + +func (codec *uint8Codec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteUint8(*((*uint8)(ptr))) +} + +func (codec *uint8Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*uint8)(ptr)) == 0 +} + +type uint16Codec struct { +} + +func (codec *uint16Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.ReadNil() { + *((*uint16)(ptr)) = iter.ReadUint16() + } +} + +func (codec *uint16Codec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteUint16(*((*uint16)(ptr))) +} + +func (codec *uint16Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*uint16)(ptr)) == 0 +} + +type uint32Codec struct { +} + +func (codec *uint32Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.ReadNil() { + *((*uint32)(ptr)) = iter.ReadUint32() + } +} + +func (codec *uint32Codec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteUint32(*((*uint32)(ptr))) +} + +func (codec *uint32Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*uint32)(ptr)) == 0 +} + +type uint64Codec struct { +} + +func (codec *uint64Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.ReadNil() { + *((*uint64)(ptr)) = iter.ReadUint64() + } +} + +func (codec *uint64Codec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteUint64(*((*uint64)(ptr))) +} + +func (codec *uint64Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*uint64)(ptr)) == 0 +} + +type float32Codec struct { +} + +func (codec *float32Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.ReadNil() { + *((*float32)(ptr)) = iter.ReadFloat32() + } +} + +func (codec *float32Codec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteFloat32(*((*float32)(ptr))) +} + +func (codec *float32Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*float32)(ptr)) == 0 +} + +type float64Codec struct { +} + +func (codec *float64Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.ReadNil() { + *((*float64)(ptr)) = iter.ReadFloat64() + } +} + +func (codec *float64Codec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteFloat64(*((*float64)(ptr))) +} + +func (codec *float64Codec) IsEmpty(ptr unsafe.Pointer) bool { + return *((*float64)(ptr)) == 0 +} + +type boolCodec struct { +} + +func (codec *boolCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.ReadNil() { + *((*bool)(ptr)) = iter.ReadBool() + } +} + +func (codec *boolCodec) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteBool(*((*bool)(ptr))) +} + +func (codec *boolCodec) IsEmpty(ptr unsafe.Pointer) bool { + return !(*((*bool)(ptr))) +} + +type base64Codec struct { + sliceType *reflect2.UnsafeSliceType + sliceDecoder ValDecoder +} + +func (codec *base64Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { + if iter.ReadNil() { + codec.sliceType.UnsafeSetNil(ptr) + return + } + switch iter.WhatIsNext() { + case StringValue: + src := iter.ReadString() + dst, err := base64.StdEncoding.DecodeString(src) + if err != nil { + iter.ReportError("decode base64", err.Error()) + } else { + codec.sliceType.UnsafeSet(ptr, unsafe.Pointer(&dst)) + } + case ArrayValue: + codec.sliceDecoder.Decode(ptr, iter) + default: + iter.ReportError("base64Codec", "invalid input") + } +} + +func (codec *base64Codec) Encode(ptr unsafe.Pointer, stream *Stream) { + if codec.sliceType.UnsafeIsNil(ptr) { + stream.WriteNil() + return + } + src := *((*[]byte)(ptr)) + encoding := base64.StdEncoding + stream.writeByte('"') + if len(src) != 0 { + size := encoding.EncodedLen(len(src)) + buf := make([]byte, size) + encoding.Encode(buf, src) + stream.buf = append(stream.buf, buf...) + } + stream.writeByte('"') +} + +func (codec *base64Codec) IsEmpty(ptr unsafe.Pointer) bool { + return len(*((*[]byte)(ptr))) == 0 +} diff --git a/vendor/github.com/json-iterator/go/reflect_optional.go b/vendor/github.com/json-iterator/go/reflect_optional.go new file mode 100644 index 0000000000000..43ec71d6dadf3 --- /dev/null +++ b/vendor/github.com/json-iterator/go/reflect_optional.go @@ -0,0 +1,133 @@ +package jsoniter + +import ( + "github.com/modern-go/reflect2" + "reflect" + "unsafe" +) + +func decoderOfOptional(ctx *ctx, typ reflect2.Type) ValDecoder { + ptrType := typ.(*reflect2.UnsafePtrType) + elemType := ptrType.Elem() + decoder := decoderOfType(ctx, elemType) + if ctx.prefix == "" && elemType.Kind() == reflect.Ptr { + return &dereferenceDecoder{elemType, decoder} + } + return &OptionalDecoder{elemType, decoder} +} + +func encoderOfOptional(ctx *ctx, typ reflect2.Type) ValEncoder { + ptrType := typ.(*reflect2.UnsafePtrType) + elemType := ptrType.Elem() + elemEncoder := encoderOfType(ctx, elemType) + encoder := &OptionalEncoder{elemEncoder} + return encoder +} + +type OptionalDecoder struct { + ValueType reflect2.Type + ValueDecoder ValDecoder +} + +func (decoder *OptionalDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + if iter.ReadNil() { + *((*unsafe.Pointer)(ptr)) = nil + } else { + if *((*unsafe.Pointer)(ptr)) == nil { + //pointer to null, we have to allocate memory to hold the value + newPtr := decoder.ValueType.UnsafeNew() + decoder.ValueDecoder.Decode(newPtr, iter) + *((*unsafe.Pointer)(ptr)) = newPtr + } else { + //reuse existing instance + decoder.ValueDecoder.Decode(*((*unsafe.Pointer)(ptr)), iter) + } + } +} + +type dereferenceDecoder struct { + // only to deference a pointer + valueType reflect2.Type + valueDecoder ValDecoder +} + +func (decoder *dereferenceDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + if *((*unsafe.Pointer)(ptr)) == nil { + //pointer to null, we have to allocate memory to hold the value + newPtr := decoder.valueType.UnsafeNew() + decoder.valueDecoder.Decode(newPtr, iter) + *((*unsafe.Pointer)(ptr)) = newPtr + } else { + //reuse existing instance + decoder.valueDecoder.Decode(*((*unsafe.Pointer)(ptr)), iter) + } +} + +type OptionalEncoder struct { + ValueEncoder ValEncoder +} + +func (encoder *OptionalEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + if *((*unsafe.Pointer)(ptr)) == nil { + stream.WriteNil() + } else { + encoder.ValueEncoder.Encode(*((*unsafe.Pointer)(ptr)), stream) + } +} + +func (encoder *OptionalEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return *((*unsafe.Pointer)(ptr)) == nil +} + +type dereferenceEncoder struct { + ValueEncoder ValEncoder +} + +func (encoder *dereferenceEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + if *((*unsafe.Pointer)(ptr)) == nil { + stream.WriteNil() + } else { + encoder.ValueEncoder.Encode(*((*unsafe.Pointer)(ptr)), stream) + } +} + +func (encoder *dereferenceEncoder) IsEmpty(ptr unsafe.Pointer) bool { + dePtr := *((*unsafe.Pointer)(ptr)) + if dePtr == nil { + return true + } + return encoder.ValueEncoder.IsEmpty(dePtr) +} + +func (encoder *dereferenceEncoder) IsEmbeddedPtrNil(ptr unsafe.Pointer) bool { + deReferenced := *((*unsafe.Pointer)(ptr)) + if deReferenced == nil { + return true + } + isEmbeddedPtrNil, converted := encoder.ValueEncoder.(IsEmbeddedPtrNil) + if !converted { + return false + } + fieldPtr := unsafe.Pointer(deReferenced) + return isEmbeddedPtrNil.IsEmbeddedPtrNil(fieldPtr) +} + +type referenceEncoder struct { + encoder ValEncoder +} + +func (encoder *referenceEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + encoder.encoder.Encode(unsafe.Pointer(&ptr), stream) +} + +func (encoder *referenceEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return encoder.encoder.IsEmpty(unsafe.Pointer(&ptr)) +} + +type referenceDecoder struct { + decoder ValDecoder +} + +func (decoder *referenceDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + decoder.decoder.Decode(unsafe.Pointer(&ptr), iter) +} diff --git a/vendor/github.com/json-iterator/go/reflect_slice.go b/vendor/github.com/json-iterator/go/reflect_slice.go new file mode 100644 index 0000000000000..9441d79df33b4 --- /dev/null +++ b/vendor/github.com/json-iterator/go/reflect_slice.go @@ -0,0 +1,99 @@ +package jsoniter + +import ( + "fmt" + "github.com/modern-go/reflect2" + "io" + "unsafe" +) + +func decoderOfSlice(ctx *ctx, typ reflect2.Type) ValDecoder { + sliceType := typ.(*reflect2.UnsafeSliceType) + decoder := decoderOfType(ctx.append("[sliceElem]"), sliceType.Elem()) + return &sliceDecoder{sliceType, decoder} +} + +func encoderOfSlice(ctx *ctx, typ reflect2.Type) ValEncoder { + sliceType := typ.(*reflect2.UnsafeSliceType) + encoder := encoderOfType(ctx.append("[sliceElem]"), sliceType.Elem()) + return &sliceEncoder{sliceType, encoder} +} + +type sliceEncoder struct { + sliceType *reflect2.UnsafeSliceType + elemEncoder ValEncoder +} + +func (encoder *sliceEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + if encoder.sliceType.UnsafeIsNil(ptr) { + stream.WriteNil() + return + } + length := encoder.sliceType.UnsafeLengthOf(ptr) + if length == 0 { + stream.WriteEmptyArray() + return + } + stream.WriteArrayStart() + encoder.elemEncoder.Encode(encoder.sliceType.UnsafeGetIndex(ptr, 0), stream) + for i := 1; i < length; i++ { + stream.WriteMore() + elemPtr := encoder.sliceType.UnsafeGetIndex(ptr, i) + encoder.elemEncoder.Encode(elemPtr, stream) + } + stream.WriteArrayEnd() + if stream.Error != nil && stream.Error != io.EOF { + stream.Error = fmt.Errorf("%v: %s", encoder.sliceType, stream.Error.Error()) + } +} + +func (encoder *sliceEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return encoder.sliceType.UnsafeLengthOf(ptr) == 0 +} + +type sliceDecoder struct { + sliceType *reflect2.UnsafeSliceType + elemDecoder ValDecoder +} + +func (decoder *sliceDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + decoder.doDecode(ptr, iter) + if iter.Error != nil && iter.Error != io.EOF { + iter.Error = fmt.Errorf("%v: %s", decoder.sliceType, iter.Error.Error()) + } +} + +func (decoder *sliceDecoder) doDecode(ptr unsafe.Pointer, iter *Iterator) { + c := iter.nextToken() + sliceType := decoder.sliceType + if c == 'n' { + iter.skipThreeBytes('u', 'l', 'l') + sliceType.UnsafeSetNil(ptr) + return + } + if c != '[' { + iter.ReportError("decode slice", "expect [ or n, but found "+string([]byte{c})) + return + } + c = iter.nextToken() + if c == ']' { + sliceType.UnsafeSet(ptr, sliceType.UnsafeMakeSlice(0, 0)) + return + } + iter.unreadByte() + sliceType.UnsafeGrow(ptr, 1) + elemPtr := sliceType.UnsafeGetIndex(ptr, 0) + decoder.elemDecoder.Decode(elemPtr, iter) + length := 1 + for c = iter.nextToken(); c == ','; c = iter.nextToken() { + idx := length + length += 1 + sliceType.UnsafeGrow(ptr, length) + elemPtr = sliceType.UnsafeGetIndex(ptr, idx) + decoder.elemDecoder.Decode(elemPtr, iter) + } + if c != ']' { + iter.ReportError("decode slice", "expect ], but found "+string([]byte{c})) + return + } +} diff --git a/vendor/github.com/json-iterator/go/reflect_struct_decoder.go b/vendor/github.com/json-iterator/go/reflect_struct_decoder.go new file mode 100644 index 0000000000000..5ad5cc561af2c --- /dev/null +++ b/vendor/github.com/json-iterator/go/reflect_struct_decoder.go @@ -0,0 +1,1092 @@ +package jsoniter + +import ( + "fmt" + "io" + "strings" + "unsafe" + + "github.com/modern-go/reflect2" +) + +func decoderOfStruct(ctx *ctx, typ reflect2.Type) ValDecoder { + bindings := map[string]*Binding{} + structDescriptor := describeStruct(ctx, typ) + for _, binding := range structDescriptor.Fields { + for _, fromName := range binding.FromNames { + old := bindings[fromName] + if old == nil { + bindings[fromName] = binding + continue + } + ignoreOld, ignoreNew := resolveConflictBinding(ctx.frozenConfig, old, binding) + if ignoreOld { + delete(bindings, fromName) + } + if !ignoreNew { + bindings[fromName] = binding + } + } + } + fields := map[string]*structFieldDecoder{} + for k, binding := range bindings { + fields[k] = binding.Decoder.(*structFieldDecoder) + } + + if !ctx.caseSensitive() { + for k, binding := range bindings { + if _, found := fields[strings.ToLower(k)]; !found { + fields[strings.ToLower(k)] = binding.Decoder.(*structFieldDecoder) + } + } + } + + return createStructDecoder(ctx, typ, fields) +} + +func createStructDecoder(ctx *ctx, typ reflect2.Type, fields map[string]*structFieldDecoder) ValDecoder { + if ctx.disallowUnknownFields { + return &generalStructDecoder{typ: typ, fields: fields, disallowUnknownFields: true} + } + knownHash := map[int64]struct{}{ + 0: {}, + } + + switch len(fields) { + case 0: + return &skipObjectDecoder{typ} + case 1: + for fieldName, fieldDecoder := range fields { + fieldHash := calcHash(fieldName, ctx.caseSensitive()) + _, known := knownHash[fieldHash] + if known { + return &generalStructDecoder{typ, fields, false} + } + knownHash[fieldHash] = struct{}{} + return &oneFieldStructDecoder{typ, fieldHash, fieldDecoder} + } + case 2: + var fieldHash1 int64 + var fieldHash2 int64 + var fieldDecoder1 *structFieldDecoder + var fieldDecoder2 *structFieldDecoder + for fieldName, fieldDecoder := range fields { + fieldHash := calcHash(fieldName, ctx.caseSensitive()) + _, known := knownHash[fieldHash] + if known { + return &generalStructDecoder{typ, fields, false} + } + knownHash[fieldHash] = struct{}{} + if fieldHash1 == 0 { + fieldHash1 = fieldHash + fieldDecoder1 = fieldDecoder + } else { + fieldHash2 = fieldHash + fieldDecoder2 = fieldDecoder + } + } + return &twoFieldsStructDecoder{typ, fieldHash1, fieldDecoder1, fieldHash2, fieldDecoder2} + case 3: + var fieldName1 int64 + var fieldName2 int64 + var fieldName3 int64 + var fieldDecoder1 *structFieldDecoder + var fieldDecoder2 *structFieldDecoder + var fieldDecoder3 *structFieldDecoder + for fieldName, fieldDecoder := range fields { + fieldHash := calcHash(fieldName, ctx.caseSensitive()) + _, known := knownHash[fieldHash] + if known { + return &generalStructDecoder{typ, fields, false} + } + knownHash[fieldHash] = struct{}{} + if fieldName1 == 0 { + fieldName1 = fieldHash + fieldDecoder1 = fieldDecoder + } else if fieldName2 == 0 { + fieldName2 = fieldHash + fieldDecoder2 = fieldDecoder + } else { + fieldName3 = fieldHash + fieldDecoder3 = fieldDecoder + } + } + return &threeFieldsStructDecoder{typ, + fieldName1, fieldDecoder1, + fieldName2, fieldDecoder2, + fieldName3, fieldDecoder3} + case 4: + var fieldName1 int64 + var fieldName2 int64 + var fieldName3 int64 + var fieldName4 int64 + var fieldDecoder1 *structFieldDecoder + var fieldDecoder2 *structFieldDecoder + var fieldDecoder3 *structFieldDecoder + var fieldDecoder4 *structFieldDecoder + for fieldName, fieldDecoder := range fields { + fieldHash := calcHash(fieldName, ctx.caseSensitive()) + _, known := knownHash[fieldHash] + if known { + return &generalStructDecoder{typ, fields, false} + } + knownHash[fieldHash] = struct{}{} + if fieldName1 == 0 { + fieldName1 = fieldHash + fieldDecoder1 = fieldDecoder + } else if fieldName2 == 0 { + fieldName2 = fieldHash + fieldDecoder2 = fieldDecoder + } else if fieldName3 == 0 { + fieldName3 = fieldHash + fieldDecoder3 = fieldDecoder + } else { + fieldName4 = fieldHash + fieldDecoder4 = fieldDecoder + } + } + return &fourFieldsStructDecoder{typ, + fieldName1, fieldDecoder1, + fieldName2, fieldDecoder2, + fieldName3, fieldDecoder3, + fieldName4, fieldDecoder4} + case 5: + var fieldName1 int64 + var fieldName2 int64 + var fieldName3 int64 + var fieldName4 int64 + var fieldName5 int64 + var fieldDecoder1 *structFieldDecoder + var fieldDecoder2 *structFieldDecoder + var fieldDecoder3 *structFieldDecoder + var fieldDecoder4 *structFieldDecoder + var fieldDecoder5 *structFieldDecoder + for fieldName, fieldDecoder := range fields { + fieldHash := calcHash(fieldName, ctx.caseSensitive()) + _, known := knownHash[fieldHash] + if known { + return &generalStructDecoder{typ, fields, false} + } + knownHash[fieldHash] = struct{}{} + if fieldName1 == 0 { + fieldName1 = fieldHash + fieldDecoder1 = fieldDecoder + } else if fieldName2 == 0 { + fieldName2 = fieldHash + fieldDecoder2 = fieldDecoder + } else if fieldName3 == 0 { + fieldName3 = fieldHash + fieldDecoder3 = fieldDecoder + } else if fieldName4 == 0 { + fieldName4 = fieldHash + fieldDecoder4 = fieldDecoder + } else { + fieldName5 = fieldHash + fieldDecoder5 = fieldDecoder + } + } + return &fiveFieldsStructDecoder{typ, + fieldName1, fieldDecoder1, + fieldName2, fieldDecoder2, + fieldName3, fieldDecoder3, + fieldName4, fieldDecoder4, + fieldName5, fieldDecoder5} + case 6: + var fieldName1 int64 + var fieldName2 int64 + var fieldName3 int64 + var fieldName4 int64 + var fieldName5 int64 + var fieldName6 int64 + var fieldDecoder1 *structFieldDecoder + var fieldDecoder2 *structFieldDecoder + var fieldDecoder3 *structFieldDecoder + var fieldDecoder4 *structFieldDecoder + var fieldDecoder5 *structFieldDecoder + var fieldDecoder6 *structFieldDecoder + for fieldName, fieldDecoder := range fields { + fieldHash := calcHash(fieldName, ctx.caseSensitive()) + _, known := knownHash[fieldHash] + if known { + return &generalStructDecoder{typ, fields, false} + } + knownHash[fieldHash] = struct{}{} + if fieldName1 == 0 { + fieldName1 = fieldHash + fieldDecoder1 = fieldDecoder + } else if fieldName2 == 0 { + fieldName2 = fieldHash + fieldDecoder2 = fieldDecoder + } else if fieldName3 == 0 { + fieldName3 = fieldHash + fieldDecoder3 = fieldDecoder + } else if fieldName4 == 0 { + fieldName4 = fieldHash + fieldDecoder4 = fieldDecoder + } else if fieldName5 == 0 { + fieldName5 = fieldHash + fieldDecoder5 = fieldDecoder + } else { + fieldName6 = fieldHash + fieldDecoder6 = fieldDecoder + } + } + return &sixFieldsStructDecoder{typ, + fieldName1, fieldDecoder1, + fieldName2, fieldDecoder2, + fieldName3, fieldDecoder3, + fieldName4, fieldDecoder4, + fieldName5, fieldDecoder5, + fieldName6, fieldDecoder6} + case 7: + var fieldName1 int64 + var fieldName2 int64 + var fieldName3 int64 + var fieldName4 int64 + var fieldName5 int64 + var fieldName6 int64 + var fieldName7 int64 + var fieldDecoder1 *structFieldDecoder + var fieldDecoder2 *structFieldDecoder + var fieldDecoder3 *structFieldDecoder + var fieldDecoder4 *structFieldDecoder + var fieldDecoder5 *structFieldDecoder + var fieldDecoder6 *structFieldDecoder + var fieldDecoder7 *structFieldDecoder + for fieldName, fieldDecoder := range fields { + fieldHash := calcHash(fieldName, ctx.caseSensitive()) + _, known := knownHash[fieldHash] + if known { + return &generalStructDecoder{typ, fields, false} + } + knownHash[fieldHash] = struct{}{} + if fieldName1 == 0 { + fieldName1 = fieldHash + fieldDecoder1 = fieldDecoder + } else if fieldName2 == 0 { + fieldName2 = fieldHash + fieldDecoder2 = fieldDecoder + } else if fieldName3 == 0 { + fieldName3 = fieldHash + fieldDecoder3 = fieldDecoder + } else if fieldName4 == 0 { + fieldName4 = fieldHash + fieldDecoder4 = fieldDecoder + } else if fieldName5 == 0 { + fieldName5 = fieldHash + fieldDecoder5 = fieldDecoder + } else if fieldName6 == 0 { + fieldName6 = fieldHash + fieldDecoder6 = fieldDecoder + } else { + fieldName7 = fieldHash + fieldDecoder7 = fieldDecoder + } + } + return &sevenFieldsStructDecoder{typ, + fieldName1, fieldDecoder1, + fieldName2, fieldDecoder2, + fieldName3, fieldDecoder3, + fieldName4, fieldDecoder4, + fieldName5, fieldDecoder5, + fieldName6, fieldDecoder6, + fieldName7, fieldDecoder7} + case 8: + var fieldName1 int64 + var fieldName2 int64 + var fieldName3 int64 + var fieldName4 int64 + var fieldName5 int64 + var fieldName6 int64 + var fieldName7 int64 + var fieldName8 int64 + var fieldDecoder1 *structFieldDecoder + var fieldDecoder2 *structFieldDecoder + var fieldDecoder3 *structFieldDecoder + var fieldDecoder4 *structFieldDecoder + var fieldDecoder5 *structFieldDecoder + var fieldDecoder6 *structFieldDecoder + var fieldDecoder7 *structFieldDecoder + var fieldDecoder8 *structFieldDecoder + for fieldName, fieldDecoder := range fields { + fieldHash := calcHash(fieldName, ctx.caseSensitive()) + _, known := knownHash[fieldHash] + if known { + return &generalStructDecoder{typ, fields, false} + } + knownHash[fieldHash] = struct{}{} + if fieldName1 == 0 { + fieldName1 = fieldHash + fieldDecoder1 = fieldDecoder + } else if fieldName2 == 0 { + fieldName2 = fieldHash + fieldDecoder2 = fieldDecoder + } else if fieldName3 == 0 { + fieldName3 = fieldHash + fieldDecoder3 = fieldDecoder + } else if fieldName4 == 0 { + fieldName4 = fieldHash + fieldDecoder4 = fieldDecoder + } else if fieldName5 == 0 { + fieldName5 = fieldHash + fieldDecoder5 = fieldDecoder + } else if fieldName6 == 0 { + fieldName6 = fieldHash + fieldDecoder6 = fieldDecoder + } else if fieldName7 == 0 { + fieldName7 = fieldHash + fieldDecoder7 = fieldDecoder + } else { + fieldName8 = fieldHash + fieldDecoder8 = fieldDecoder + } + } + return &eightFieldsStructDecoder{typ, + fieldName1, fieldDecoder1, + fieldName2, fieldDecoder2, + fieldName3, fieldDecoder3, + fieldName4, fieldDecoder4, + fieldName5, fieldDecoder5, + fieldName6, fieldDecoder6, + fieldName7, fieldDecoder7, + fieldName8, fieldDecoder8} + case 9: + var fieldName1 int64 + var fieldName2 int64 + var fieldName3 int64 + var fieldName4 int64 + var fieldName5 int64 + var fieldName6 int64 + var fieldName7 int64 + var fieldName8 int64 + var fieldName9 int64 + var fieldDecoder1 *structFieldDecoder + var fieldDecoder2 *structFieldDecoder + var fieldDecoder3 *structFieldDecoder + var fieldDecoder4 *structFieldDecoder + var fieldDecoder5 *structFieldDecoder + var fieldDecoder6 *structFieldDecoder + var fieldDecoder7 *structFieldDecoder + var fieldDecoder8 *structFieldDecoder + var fieldDecoder9 *structFieldDecoder + for fieldName, fieldDecoder := range fields { + fieldHash := calcHash(fieldName, ctx.caseSensitive()) + _, known := knownHash[fieldHash] + if known { + return &generalStructDecoder{typ, fields, false} + } + knownHash[fieldHash] = struct{}{} + if fieldName1 == 0 { + fieldName1 = fieldHash + fieldDecoder1 = fieldDecoder + } else if fieldName2 == 0 { + fieldName2 = fieldHash + fieldDecoder2 = fieldDecoder + } else if fieldName3 == 0 { + fieldName3 = fieldHash + fieldDecoder3 = fieldDecoder + } else if fieldName4 == 0 { + fieldName4 = fieldHash + fieldDecoder4 = fieldDecoder + } else if fieldName5 == 0 { + fieldName5 = fieldHash + fieldDecoder5 = fieldDecoder + } else if fieldName6 == 0 { + fieldName6 = fieldHash + fieldDecoder6 = fieldDecoder + } else if fieldName7 == 0 { + fieldName7 = fieldHash + fieldDecoder7 = fieldDecoder + } else if fieldName8 == 0 { + fieldName8 = fieldHash + fieldDecoder8 = fieldDecoder + } else { + fieldName9 = fieldHash + fieldDecoder9 = fieldDecoder + } + } + return &nineFieldsStructDecoder{typ, + fieldName1, fieldDecoder1, + fieldName2, fieldDecoder2, + fieldName3, fieldDecoder3, + fieldName4, fieldDecoder4, + fieldName5, fieldDecoder5, + fieldName6, fieldDecoder6, + fieldName7, fieldDecoder7, + fieldName8, fieldDecoder8, + fieldName9, fieldDecoder9} + case 10: + var fieldName1 int64 + var fieldName2 int64 + var fieldName3 int64 + var fieldName4 int64 + var fieldName5 int64 + var fieldName6 int64 + var fieldName7 int64 + var fieldName8 int64 + var fieldName9 int64 + var fieldName10 int64 + var fieldDecoder1 *structFieldDecoder + var fieldDecoder2 *structFieldDecoder + var fieldDecoder3 *structFieldDecoder + var fieldDecoder4 *structFieldDecoder + var fieldDecoder5 *structFieldDecoder + var fieldDecoder6 *structFieldDecoder + var fieldDecoder7 *structFieldDecoder + var fieldDecoder8 *structFieldDecoder + var fieldDecoder9 *structFieldDecoder + var fieldDecoder10 *structFieldDecoder + for fieldName, fieldDecoder := range fields { + fieldHash := calcHash(fieldName, ctx.caseSensitive()) + _, known := knownHash[fieldHash] + if known { + return &generalStructDecoder{typ, fields, false} + } + knownHash[fieldHash] = struct{}{} + if fieldName1 == 0 { + fieldName1 = fieldHash + fieldDecoder1 = fieldDecoder + } else if fieldName2 == 0 { + fieldName2 = fieldHash + fieldDecoder2 = fieldDecoder + } else if fieldName3 == 0 { + fieldName3 = fieldHash + fieldDecoder3 = fieldDecoder + } else if fieldName4 == 0 { + fieldName4 = fieldHash + fieldDecoder4 = fieldDecoder + } else if fieldName5 == 0 { + fieldName5 = fieldHash + fieldDecoder5 = fieldDecoder + } else if fieldName6 == 0 { + fieldName6 = fieldHash + fieldDecoder6 = fieldDecoder + } else if fieldName7 == 0 { + fieldName7 = fieldHash + fieldDecoder7 = fieldDecoder + } else if fieldName8 == 0 { + fieldName8 = fieldHash + fieldDecoder8 = fieldDecoder + } else if fieldName9 == 0 { + fieldName9 = fieldHash + fieldDecoder9 = fieldDecoder + } else { + fieldName10 = fieldHash + fieldDecoder10 = fieldDecoder + } + } + return &tenFieldsStructDecoder{typ, + fieldName1, fieldDecoder1, + fieldName2, fieldDecoder2, + fieldName3, fieldDecoder3, + fieldName4, fieldDecoder4, + fieldName5, fieldDecoder5, + fieldName6, fieldDecoder6, + fieldName7, fieldDecoder7, + fieldName8, fieldDecoder8, + fieldName9, fieldDecoder9, + fieldName10, fieldDecoder10} + } + return &generalStructDecoder{typ, fields, false} +} + +type generalStructDecoder struct { + typ reflect2.Type + fields map[string]*structFieldDecoder + disallowUnknownFields bool +} + +func (decoder *generalStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.readObjectStart() { + return + } + if !iter.incrementDepth() { + return + } + var c byte + for c = ','; c == ','; c = iter.nextToken() { + decoder.decodeOneField(ptr, iter) + } + if iter.Error != nil && iter.Error != io.EOF { + iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) + } + if c != '}' { + iter.ReportError("struct Decode", `expect }, but found `+string([]byte{c})) + } + iter.decrementDepth() +} + +func (decoder *generalStructDecoder) decodeOneField(ptr unsafe.Pointer, iter *Iterator) { + var field string + var fieldDecoder *structFieldDecoder + if iter.cfg.objectFieldMustBeSimpleString { + fieldBytes := iter.ReadStringAsSlice() + field = *(*string)(unsafe.Pointer(&fieldBytes)) + fieldDecoder = decoder.fields[field] + if fieldDecoder == nil && !iter.cfg.caseSensitive { + fieldDecoder = decoder.fields[strings.ToLower(field)] + } + } else { + field = iter.ReadString() + fieldDecoder = decoder.fields[field] + if fieldDecoder == nil && !iter.cfg.caseSensitive { + fieldDecoder = decoder.fields[strings.ToLower(field)] + } + } + if fieldDecoder == nil { + if decoder.disallowUnknownFields { + msg := "found unknown field: " + field + iter.ReportError("ReadObject", msg) + } + c := iter.nextToken() + if c != ':' { + iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c})) + } + iter.Skip() + return + } + c := iter.nextToken() + if c != ':' { + iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c})) + } + fieldDecoder.Decode(ptr, iter) +} + +type skipObjectDecoder struct { + typ reflect2.Type +} + +func (decoder *skipObjectDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + valueType := iter.WhatIsNext() + if valueType != ObjectValue && valueType != NilValue { + iter.ReportError("skipObjectDecoder", "expect object or null") + return + } + iter.Skip() +} + +type oneFieldStructDecoder struct { + typ reflect2.Type + fieldHash int64 + fieldDecoder *structFieldDecoder +} + +func (decoder *oneFieldStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.readObjectStart() { + return + } + if !iter.incrementDepth() { + return + } + for { + if iter.readFieldHash() == decoder.fieldHash { + decoder.fieldDecoder.Decode(ptr, iter) + } else { + iter.Skip() + } + if iter.isObjectEnd() { + break + } + } + if iter.Error != nil && iter.Error != io.EOF { + iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) + } + iter.decrementDepth() +} + +type twoFieldsStructDecoder struct { + typ reflect2.Type + fieldHash1 int64 + fieldDecoder1 *structFieldDecoder + fieldHash2 int64 + fieldDecoder2 *structFieldDecoder +} + +func (decoder *twoFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.readObjectStart() { + return + } + if !iter.incrementDepth() { + return + } + for { + switch iter.readFieldHash() { + case decoder.fieldHash1: + decoder.fieldDecoder1.Decode(ptr, iter) + case decoder.fieldHash2: + decoder.fieldDecoder2.Decode(ptr, iter) + default: + iter.Skip() + } + if iter.isObjectEnd() { + break + } + } + if iter.Error != nil && iter.Error != io.EOF { + iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) + } + iter.decrementDepth() +} + +type threeFieldsStructDecoder struct { + typ reflect2.Type + fieldHash1 int64 + fieldDecoder1 *structFieldDecoder + fieldHash2 int64 + fieldDecoder2 *structFieldDecoder + fieldHash3 int64 + fieldDecoder3 *structFieldDecoder +} + +func (decoder *threeFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.readObjectStart() { + return + } + if !iter.incrementDepth() { + return + } + for { + switch iter.readFieldHash() { + case decoder.fieldHash1: + decoder.fieldDecoder1.Decode(ptr, iter) + case decoder.fieldHash2: + decoder.fieldDecoder2.Decode(ptr, iter) + case decoder.fieldHash3: + decoder.fieldDecoder3.Decode(ptr, iter) + default: + iter.Skip() + } + if iter.isObjectEnd() { + break + } + } + if iter.Error != nil && iter.Error != io.EOF { + iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) + } + iter.decrementDepth() +} + +type fourFieldsStructDecoder struct { + typ reflect2.Type + fieldHash1 int64 + fieldDecoder1 *structFieldDecoder + fieldHash2 int64 + fieldDecoder2 *structFieldDecoder + fieldHash3 int64 + fieldDecoder3 *structFieldDecoder + fieldHash4 int64 + fieldDecoder4 *structFieldDecoder +} + +func (decoder *fourFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.readObjectStart() { + return + } + if !iter.incrementDepth() { + return + } + for { + switch iter.readFieldHash() { + case decoder.fieldHash1: + decoder.fieldDecoder1.Decode(ptr, iter) + case decoder.fieldHash2: + decoder.fieldDecoder2.Decode(ptr, iter) + case decoder.fieldHash3: + decoder.fieldDecoder3.Decode(ptr, iter) + case decoder.fieldHash4: + decoder.fieldDecoder4.Decode(ptr, iter) + default: + iter.Skip() + } + if iter.isObjectEnd() { + break + } + } + if iter.Error != nil && iter.Error != io.EOF { + iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) + } + iter.decrementDepth() +} + +type fiveFieldsStructDecoder struct { + typ reflect2.Type + fieldHash1 int64 + fieldDecoder1 *structFieldDecoder + fieldHash2 int64 + fieldDecoder2 *structFieldDecoder + fieldHash3 int64 + fieldDecoder3 *structFieldDecoder + fieldHash4 int64 + fieldDecoder4 *structFieldDecoder + fieldHash5 int64 + fieldDecoder5 *structFieldDecoder +} + +func (decoder *fiveFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.readObjectStart() { + return + } + if !iter.incrementDepth() { + return + } + for { + switch iter.readFieldHash() { + case decoder.fieldHash1: + decoder.fieldDecoder1.Decode(ptr, iter) + case decoder.fieldHash2: + decoder.fieldDecoder2.Decode(ptr, iter) + case decoder.fieldHash3: + decoder.fieldDecoder3.Decode(ptr, iter) + case decoder.fieldHash4: + decoder.fieldDecoder4.Decode(ptr, iter) + case decoder.fieldHash5: + decoder.fieldDecoder5.Decode(ptr, iter) + default: + iter.Skip() + } + if iter.isObjectEnd() { + break + } + } + if iter.Error != nil && iter.Error != io.EOF { + iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) + } + iter.decrementDepth() +} + +type sixFieldsStructDecoder struct { + typ reflect2.Type + fieldHash1 int64 + fieldDecoder1 *structFieldDecoder + fieldHash2 int64 + fieldDecoder2 *structFieldDecoder + fieldHash3 int64 + fieldDecoder3 *structFieldDecoder + fieldHash4 int64 + fieldDecoder4 *structFieldDecoder + fieldHash5 int64 + fieldDecoder5 *structFieldDecoder + fieldHash6 int64 + fieldDecoder6 *structFieldDecoder +} + +func (decoder *sixFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.readObjectStart() { + return + } + if !iter.incrementDepth() { + return + } + for { + switch iter.readFieldHash() { + case decoder.fieldHash1: + decoder.fieldDecoder1.Decode(ptr, iter) + case decoder.fieldHash2: + decoder.fieldDecoder2.Decode(ptr, iter) + case decoder.fieldHash3: + decoder.fieldDecoder3.Decode(ptr, iter) + case decoder.fieldHash4: + decoder.fieldDecoder4.Decode(ptr, iter) + case decoder.fieldHash5: + decoder.fieldDecoder5.Decode(ptr, iter) + case decoder.fieldHash6: + decoder.fieldDecoder6.Decode(ptr, iter) + default: + iter.Skip() + } + if iter.isObjectEnd() { + break + } + } + if iter.Error != nil && iter.Error != io.EOF { + iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) + } + iter.decrementDepth() +} + +type sevenFieldsStructDecoder struct { + typ reflect2.Type + fieldHash1 int64 + fieldDecoder1 *structFieldDecoder + fieldHash2 int64 + fieldDecoder2 *structFieldDecoder + fieldHash3 int64 + fieldDecoder3 *structFieldDecoder + fieldHash4 int64 + fieldDecoder4 *structFieldDecoder + fieldHash5 int64 + fieldDecoder5 *structFieldDecoder + fieldHash6 int64 + fieldDecoder6 *structFieldDecoder + fieldHash7 int64 + fieldDecoder7 *structFieldDecoder +} + +func (decoder *sevenFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.readObjectStart() { + return + } + if !iter.incrementDepth() { + return + } + for { + switch iter.readFieldHash() { + case decoder.fieldHash1: + decoder.fieldDecoder1.Decode(ptr, iter) + case decoder.fieldHash2: + decoder.fieldDecoder2.Decode(ptr, iter) + case decoder.fieldHash3: + decoder.fieldDecoder3.Decode(ptr, iter) + case decoder.fieldHash4: + decoder.fieldDecoder4.Decode(ptr, iter) + case decoder.fieldHash5: + decoder.fieldDecoder5.Decode(ptr, iter) + case decoder.fieldHash6: + decoder.fieldDecoder6.Decode(ptr, iter) + case decoder.fieldHash7: + decoder.fieldDecoder7.Decode(ptr, iter) + default: + iter.Skip() + } + if iter.isObjectEnd() { + break + } + } + if iter.Error != nil && iter.Error != io.EOF { + iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) + } + iter.decrementDepth() +} + +type eightFieldsStructDecoder struct { + typ reflect2.Type + fieldHash1 int64 + fieldDecoder1 *structFieldDecoder + fieldHash2 int64 + fieldDecoder2 *structFieldDecoder + fieldHash3 int64 + fieldDecoder3 *structFieldDecoder + fieldHash4 int64 + fieldDecoder4 *structFieldDecoder + fieldHash5 int64 + fieldDecoder5 *structFieldDecoder + fieldHash6 int64 + fieldDecoder6 *structFieldDecoder + fieldHash7 int64 + fieldDecoder7 *structFieldDecoder + fieldHash8 int64 + fieldDecoder8 *structFieldDecoder +} + +func (decoder *eightFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.readObjectStart() { + return + } + if !iter.incrementDepth() { + return + } + for { + switch iter.readFieldHash() { + case decoder.fieldHash1: + decoder.fieldDecoder1.Decode(ptr, iter) + case decoder.fieldHash2: + decoder.fieldDecoder2.Decode(ptr, iter) + case decoder.fieldHash3: + decoder.fieldDecoder3.Decode(ptr, iter) + case decoder.fieldHash4: + decoder.fieldDecoder4.Decode(ptr, iter) + case decoder.fieldHash5: + decoder.fieldDecoder5.Decode(ptr, iter) + case decoder.fieldHash6: + decoder.fieldDecoder6.Decode(ptr, iter) + case decoder.fieldHash7: + decoder.fieldDecoder7.Decode(ptr, iter) + case decoder.fieldHash8: + decoder.fieldDecoder8.Decode(ptr, iter) + default: + iter.Skip() + } + if iter.isObjectEnd() { + break + } + } + if iter.Error != nil && iter.Error != io.EOF { + iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) + } + iter.decrementDepth() +} + +type nineFieldsStructDecoder struct { + typ reflect2.Type + fieldHash1 int64 + fieldDecoder1 *structFieldDecoder + fieldHash2 int64 + fieldDecoder2 *structFieldDecoder + fieldHash3 int64 + fieldDecoder3 *structFieldDecoder + fieldHash4 int64 + fieldDecoder4 *structFieldDecoder + fieldHash5 int64 + fieldDecoder5 *structFieldDecoder + fieldHash6 int64 + fieldDecoder6 *structFieldDecoder + fieldHash7 int64 + fieldDecoder7 *structFieldDecoder + fieldHash8 int64 + fieldDecoder8 *structFieldDecoder + fieldHash9 int64 + fieldDecoder9 *structFieldDecoder +} + +func (decoder *nineFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.readObjectStart() { + return + } + if !iter.incrementDepth() { + return + } + for { + switch iter.readFieldHash() { + case decoder.fieldHash1: + decoder.fieldDecoder1.Decode(ptr, iter) + case decoder.fieldHash2: + decoder.fieldDecoder2.Decode(ptr, iter) + case decoder.fieldHash3: + decoder.fieldDecoder3.Decode(ptr, iter) + case decoder.fieldHash4: + decoder.fieldDecoder4.Decode(ptr, iter) + case decoder.fieldHash5: + decoder.fieldDecoder5.Decode(ptr, iter) + case decoder.fieldHash6: + decoder.fieldDecoder6.Decode(ptr, iter) + case decoder.fieldHash7: + decoder.fieldDecoder7.Decode(ptr, iter) + case decoder.fieldHash8: + decoder.fieldDecoder8.Decode(ptr, iter) + case decoder.fieldHash9: + decoder.fieldDecoder9.Decode(ptr, iter) + default: + iter.Skip() + } + if iter.isObjectEnd() { + break + } + } + if iter.Error != nil && iter.Error != io.EOF { + iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) + } + iter.decrementDepth() +} + +type tenFieldsStructDecoder struct { + typ reflect2.Type + fieldHash1 int64 + fieldDecoder1 *structFieldDecoder + fieldHash2 int64 + fieldDecoder2 *structFieldDecoder + fieldHash3 int64 + fieldDecoder3 *structFieldDecoder + fieldHash4 int64 + fieldDecoder4 *structFieldDecoder + fieldHash5 int64 + fieldDecoder5 *structFieldDecoder + fieldHash6 int64 + fieldDecoder6 *structFieldDecoder + fieldHash7 int64 + fieldDecoder7 *structFieldDecoder + fieldHash8 int64 + fieldDecoder8 *structFieldDecoder + fieldHash9 int64 + fieldDecoder9 *structFieldDecoder + fieldHash10 int64 + fieldDecoder10 *structFieldDecoder +} + +func (decoder *tenFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + if !iter.readObjectStart() { + return + } + if !iter.incrementDepth() { + return + } + for { + switch iter.readFieldHash() { + case decoder.fieldHash1: + decoder.fieldDecoder1.Decode(ptr, iter) + case decoder.fieldHash2: + decoder.fieldDecoder2.Decode(ptr, iter) + case decoder.fieldHash3: + decoder.fieldDecoder3.Decode(ptr, iter) + case decoder.fieldHash4: + decoder.fieldDecoder4.Decode(ptr, iter) + case decoder.fieldHash5: + decoder.fieldDecoder5.Decode(ptr, iter) + case decoder.fieldHash6: + decoder.fieldDecoder6.Decode(ptr, iter) + case decoder.fieldHash7: + decoder.fieldDecoder7.Decode(ptr, iter) + case decoder.fieldHash8: + decoder.fieldDecoder8.Decode(ptr, iter) + case decoder.fieldHash9: + decoder.fieldDecoder9.Decode(ptr, iter) + case decoder.fieldHash10: + decoder.fieldDecoder10.Decode(ptr, iter) + default: + iter.Skip() + } + if iter.isObjectEnd() { + break + } + } + if iter.Error != nil && iter.Error != io.EOF { + iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) + } + iter.decrementDepth() +} + +type structFieldDecoder struct { + field reflect2.StructField + fieldDecoder ValDecoder +} + +func (decoder *structFieldDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + fieldPtr := decoder.field.UnsafeGet(ptr) + decoder.fieldDecoder.Decode(fieldPtr, iter) + if iter.Error != nil && iter.Error != io.EOF { + iter.Error = fmt.Errorf("%s: %s", decoder.field.Name(), iter.Error.Error()) + } +} + +type stringModeStringDecoder struct { + elemDecoder ValDecoder + cfg *frozenConfig +} + +func (decoder *stringModeStringDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + decoder.elemDecoder.Decode(ptr, iter) + str := *((*string)(ptr)) + tempIter := decoder.cfg.BorrowIterator([]byte(str)) + defer decoder.cfg.ReturnIterator(tempIter) + *((*string)(ptr)) = tempIter.ReadString() +} + +type stringModeNumberDecoder struct { + elemDecoder ValDecoder +} + +func (decoder *stringModeNumberDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { + c := iter.nextToken() + if c != '"' { + iter.ReportError("stringModeNumberDecoder", `expect ", but found `+string([]byte{c})) + return + } + decoder.elemDecoder.Decode(ptr, iter) + if iter.Error != nil { + return + } + c = iter.readByte() + if c != '"' { + iter.ReportError("stringModeNumberDecoder", `expect ", but found `+string([]byte{c})) + return + } +} diff --git a/vendor/github.com/json-iterator/go/reflect_struct_encoder.go b/vendor/github.com/json-iterator/go/reflect_struct_encoder.go new file mode 100644 index 0000000000000..152e3ef5a93c6 --- /dev/null +++ b/vendor/github.com/json-iterator/go/reflect_struct_encoder.go @@ -0,0 +1,211 @@ +package jsoniter + +import ( + "fmt" + "github.com/modern-go/reflect2" + "io" + "reflect" + "unsafe" +) + +func encoderOfStruct(ctx *ctx, typ reflect2.Type) ValEncoder { + type bindingTo struct { + binding *Binding + toName string + ignored bool + } + orderedBindings := []*bindingTo{} + structDescriptor := describeStruct(ctx, typ) + for _, binding := range structDescriptor.Fields { + for _, toName := range binding.ToNames { + new := &bindingTo{ + binding: binding, + toName: toName, + } + for _, old := range orderedBindings { + if old.toName != toName { + continue + } + old.ignored, new.ignored = resolveConflictBinding(ctx.frozenConfig, old.binding, new.binding) + } + orderedBindings = append(orderedBindings, new) + } + } + if len(orderedBindings) == 0 { + return &emptyStructEncoder{} + } + finalOrderedFields := []structFieldTo{} + for _, bindingTo := range orderedBindings { + if !bindingTo.ignored { + finalOrderedFields = append(finalOrderedFields, structFieldTo{ + encoder: bindingTo.binding.Encoder.(*structFieldEncoder), + toName: bindingTo.toName, + }) + } + } + return &structEncoder{typ, finalOrderedFields} +} + +func createCheckIsEmpty(ctx *ctx, typ reflect2.Type) checkIsEmpty { + encoder := createEncoderOfNative(ctx, typ) + if encoder != nil { + return encoder + } + kind := typ.Kind() + switch kind { + case reflect.Interface: + return &dynamicEncoder{typ} + case reflect.Struct: + return &structEncoder{typ: typ} + case reflect.Array: + return &arrayEncoder{} + case reflect.Slice: + return &sliceEncoder{} + case reflect.Map: + return encoderOfMap(ctx, typ) + case reflect.Ptr: + return &OptionalEncoder{} + default: + return &lazyErrorEncoder{err: fmt.Errorf("unsupported type: %v", typ)} + } +} + +func resolveConflictBinding(cfg *frozenConfig, old, new *Binding) (ignoreOld, ignoreNew bool) { + newTagged := new.Field.Tag().Get(cfg.getTagKey()) != "" + oldTagged := old.Field.Tag().Get(cfg.getTagKey()) != "" + if newTagged { + if oldTagged { + if len(old.levels) > len(new.levels) { + return true, false + } else if len(new.levels) > len(old.levels) { + return false, true + } else { + return true, true + } + } else { + return true, false + } + } else { + if oldTagged { + return true, false + } + if len(old.levels) > len(new.levels) { + return true, false + } else if len(new.levels) > len(old.levels) { + return false, true + } else { + return true, true + } + } +} + +type structFieldEncoder struct { + field reflect2.StructField + fieldEncoder ValEncoder + omitempty bool +} + +func (encoder *structFieldEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + fieldPtr := encoder.field.UnsafeGet(ptr) + encoder.fieldEncoder.Encode(fieldPtr, stream) + if stream.Error != nil && stream.Error != io.EOF { + stream.Error = fmt.Errorf("%s: %s", encoder.field.Name(), stream.Error.Error()) + } +} + +func (encoder *structFieldEncoder) IsEmpty(ptr unsafe.Pointer) bool { + fieldPtr := encoder.field.UnsafeGet(ptr) + return encoder.fieldEncoder.IsEmpty(fieldPtr) +} + +func (encoder *structFieldEncoder) IsEmbeddedPtrNil(ptr unsafe.Pointer) bool { + isEmbeddedPtrNil, converted := encoder.fieldEncoder.(IsEmbeddedPtrNil) + if !converted { + return false + } + fieldPtr := encoder.field.UnsafeGet(ptr) + return isEmbeddedPtrNil.IsEmbeddedPtrNil(fieldPtr) +} + +type IsEmbeddedPtrNil interface { + IsEmbeddedPtrNil(ptr unsafe.Pointer) bool +} + +type structEncoder struct { + typ reflect2.Type + fields []structFieldTo +} + +type structFieldTo struct { + encoder *structFieldEncoder + toName string +} + +func (encoder *structEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteObjectStart() + isNotFirst := false + for _, field := range encoder.fields { + if field.encoder.omitempty && field.encoder.IsEmpty(ptr) { + continue + } + if field.encoder.IsEmbeddedPtrNil(ptr) { + continue + } + if isNotFirst { + stream.WriteMore() + } + stream.WriteObjectField(field.toName) + field.encoder.Encode(ptr, stream) + isNotFirst = true + } + stream.WriteObjectEnd() + if stream.Error != nil && stream.Error != io.EOF { + stream.Error = fmt.Errorf("%v.%s", encoder.typ, stream.Error.Error()) + } +} + +func (encoder *structEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return false +} + +type emptyStructEncoder struct { +} + +func (encoder *emptyStructEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.WriteEmptyObject() +} + +func (encoder *emptyStructEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return false +} + +type stringModeNumberEncoder struct { + elemEncoder ValEncoder +} + +func (encoder *stringModeNumberEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + stream.writeByte('"') + encoder.elemEncoder.Encode(ptr, stream) + stream.writeByte('"') +} + +func (encoder *stringModeNumberEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return encoder.elemEncoder.IsEmpty(ptr) +} + +type stringModeStringEncoder struct { + elemEncoder ValEncoder + cfg *frozenConfig +} + +func (encoder *stringModeStringEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { + tempStream := encoder.cfg.BorrowStream(nil) + tempStream.Attachment = stream.Attachment + defer encoder.cfg.ReturnStream(tempStream) + encoder.elemEncoder.Encode(ptr, tempStream) + stream.WriteString(string(tempStream.Buffer())) +} + +func (encoder *stringModeStringEncoder) IsEmpty(ptr unsafe.Pointer) bool { + return encoder.elemEncoder.IsEmpty(ptr) +} diff --git a/vendor/github.com/json-iterator/go/stream.go b/vendor/github.com/json-iterator/go/stream.go new file mode 100644 index 0000000000000..17662fdedcb55 --- /dev/null +++ b/vendor/github.com/json-iterator/go/stream.go @@ -0,0 +1,211 @@ +package jsoniter + +import ( + "io" +) + +// stream is a io.Writer like object, with JSON specific write functions. +// Error is not returned as return value, but stored as Error member on this stream instance. +type Stream struct { + cfg *frozenConfig + out io.Writer + buf []byte + Error error + indention int + Attachment interface{} // open for customized encoder +} + +// NewStream create new stream instance. +// cfg can be jsoniter.ConfigDefault. +// out can be nil if write to internal buffer. +// bufSize is the initial size for the internal buffer in bytes. +func NewStream(cfg API, out io.Writer, bufSize int) *Stream { + return &Stream{ + cfg: cfg.(*frozenConfig), + out: out, + buf: make([]byte, 0, bufSize), + Error: nil, + indention: 0, + } +} + +// Pool returns a pool can provide more stream with same configuration +func (stream *Stream) Pool() StreamPool { + return stream.cfg +} + +// Reset reuse this stream instance by assign a new writer +func (stream *Stream) Reset(out io.Writer) { + stream.out = out + stream.buf = stream.buf[:0] +} + +// Available returns how many bytes are unused in the buffer. +func (stream *Stream) Available() int { + return cap(stream.buf) - len(stream.buf) +} + +// Buffered returns the number of bytes that have been written into the current buffer. +func (stream *Stream) Buffered() int { + return len(stream.buf) +} + +// Buffer if writer is nil, use this method to take the result +func (stream *Stream) Buffer() []byte { + return stream.buf +} + +// SetBuffer allows to append to the internal buffer directly +func (stream *Stream) SetBuffer(buf []byte) { + stream.buf = buf +} + +// Write writes the contents of p into the buffer. +// It returns the number of bytes written. +// If nn < len(p), it also returns an error explaining +// why the write is short. +func (stream *Stream) Write(p []byte) (nn int, err error) { + stream.buf = append(stream.buf, p...) + if stream.out != nil { + nn, err = stream.out.Write(stream.buf) + stream.buf = stream.buf[nn:] + return + } + return len(p), nil +} + +// WriteByte writes a single byte. +func (stream *Stream) writeByte(c byte) { + stream.buf = append(stream.buf, c) +} + +func (stream *Stream) writeTwoBytes(c1 byte, c2 byte) { + stream.buf = append(stream.buf, c1, c2) +} + +func (stream *Stream) writeThreeBytes(c1 byte, c2 byte, c3 byte) { + stream.buf = append(stream.buf, c1, c2, c3) +} + +func (stream *Stream) writeFourBytes(c1 byte, c2 byte, c3 byte, c4 byte) { + stream.buf = append(stream.buf, c1, c2, c3, c4) +} + +func (stream *Stream) writeFiveBytes(c1 byte, c2 byte, c3 byte, c4 byte, c5 byte) { + stream.buf = append(stream.buf, c1, c2, c3, c4, c5) +} + +// Flush writes any buffered data to the underlying io.Writer. +func (stream *Stream) Flush() error { + if stream.out == nil { + return nil + } + if stream.Error != nil { + return stream.Error + } + n, err := stream.out.Write(stream.buf) + if err != nil { + if stream.Error == nil { + stream.Error = err + } + return err + } + stream.buf = stream.buf[n:] + return nil +} + +// WriteRaw write string out without quotes, just like []byte +func (stream *Stream) WriteRaw(s string) { + stream.buf = append(stream.buf, s...) +} + +// WriteNil write null to stream +func (stream *Stream) WriteNil() { + stream.writeFourBytes('n', 'u', 'l', 'l') +} + +// WriteTrue write true to stream +func (stream *Stream) WriteTrue() { + stream.writeFourBytes('t', 'r', 'u', 'e') +} + +// WriteFalse write false to stream +func (stream *Stream) WriteFalse() { + stream.writeFiveBytes('f', 'a', 'l', 's', 'e') +} + +// WriteBool write true or false into stream +func (stream *Stream) WriteBool(val bool) { + if val { + stream.WriteTrue() + } else { + stream.WriteFalse() + } +} + +// WriteObjectStart write { with possible indention +func (stream *Stream) WriteObjectStart() { + stream.indention += stream.cfg.indentionStep + stream.writeByte('{') + stream.writeIndention(0) +} + +// WriteObjectField write "field": with possible indention +func (stream *Stream) WriteObjectField(field string) { + stream.WriteString(field) + if stream.indention > 0 { + stream.writeTwoBytes(':', ' ') + } else { + stream.writeByte(':') + } +} + +// WriteObjectEnd write } with possible indention +func (stream *Stream) WriteObjectEnd() { + stream.writeIndention(stream.cfg.indentionStep) + stream.indention -= stream.cfg.indentionStep + stream.writeByte('}') +} + +// WriteEmptyObject write {} +func (stream *Stream) WriteEmptyObject() { + stream.writeByte('{') + stream.writeByte('}') +} + +// WriteMore write , with possible indention +func (stream *Stream) WriteMore() { + stream.writeByte(',') + stream.writeIndention(0) + stream.Flush() +} + +// WriteArrayStart write [ with possible indention +func (stream *Stream) WriteArrayStart() { + stream.indention += stream.cfg.indentionStep + stream.writeByte('[') + stream.writeIndention(0) +} + +// WriteEmptyArray write [] +func (stream *Stream) WriteEmptyArray() { + stream.writeTwoBytes('[', ']') +} + +// WriteArrayEnd write ] with possible indention +func (stream *Stream) WriteArrayEnd() { + stream.writeIndention(stream.cfg.indentionStep) + stream.indention -= stream.cfg.indentionStep + stream.writeByte(']') +} + +func (stream *Stream) writeIndention(delta int) { + if stream.indention == 0 { + return + } + stream.writeByte('\n') + toWrite := stream.indention - delta + for i := 0; i < toWrite; i++ { + stream.buf = append(stream.buf, ' ') + } +} diff --git a/vendor/github.com/json-iterator/go/stream_float.go b/vendor/github.com/json-iterator/go/stream_float.go new file mode 100644 index 0000000000000..826aa594ac6f3 --- /dev/null +++ b/vendor/github.com/json-iterator/go/stream_float.go @@ -0,0 +1,111 @@ +package jsoniter + +import ( + "fmt" + "math" + "strconv" +) + +var pow10 []uint64 + +func init() { + pow10 = []uint64{1, 10, 100, 1000, 10000, 100000, 1000000} +} + +// WriteFloat32 write float32 to stream +func (stream *Stream) WriteFloat32(val float32) { + if math.IsInf(float64(val), 0) || math.IsNaN(float64(val)) { + stream.Error = fmt.Errorf("unsupported value: %f", val) + return + } + abs := math.Abs(float64(val)) + fmt := byte('f') + // Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right. + if abs != 0 { + if float32(abs) < 1e-6 || float32(abs) >= 1e21 { + fmt = 'e' + } + } + stream.buf = strconv.AppendFloat(stream.buf, float64(val), fmt, -1, 32) +} + +// WriteFloat32Lossy write float32 to stream with ONLY 6 digits precision although much much faster +func (stream *Stream) WriteFloat32Lossy(val float32) { + if math.IsInf(float64(val), 0) || math.IsNaN(float64(val)) { + stream.Error = fmt.Errorf("unsupported value: %f", val) + return + } + if val < 0 { + stream.writeByte('-') + val = -val + } + if val > 0x4ffffff { + stream.WriteFloat32(val) + return + } + precision := 6 + exp := uint64(1000000) // 6 + lval := uint64(float64(val)*float64(exp) + 0.5) + stream.WriteUint64(lval / exp) + fval := lval % exp + if fval == 0 { + return + } + stream.writeByte('.') + for p := precision - 1; p > 0 && fval < pow10[p]; p-- { + stream.writeByte('0') + } + stream.WriteUint64(fval) + for stream.buf[len(stream.buf)-1] == '0' { + stream.buf = stream.buf[:len(stream.buf)-1] + } +} + +// WriteFloat64 write float64 to stream +func (stream *Stream) WriteFloat64(val float64) { + if math.IsInf(val, 0) || math.IsNaN(val) { + stream.Error = fmt.Errorf("unsupported value: %f", val) + return + } + abs := math.Abs(val) + fmt := byte('f') + // Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right. + if abs != 0 { + if abs < 1e-6 || abs >= 1e21 { + fmt = 'e' + } + } + stream.buf = strconv.AppendFloat(stream.buf, float64(val), fmt, -1, 64) +} + +// WriteFloat64Lossy write float64 to stream with ONLY 6 digits precision although much much faster +func (stream *Stream) WriteFloat64Lossy(val float64) { + if math.IsInf(val, 0) || math.IsNaN(val) { + stream.Error = fmt.Errorf("unsupported value: %f", val) + return + } + if val < 0 { + stream.writeByte('-') + val = -val + } + if val > 0x4ffffff { + stream.WriteFloat64(val) + return + } + precision := 6 + exp := uint64(1000000) // 6 + lval := uint64(val*float64(exp) + 0.5) + stream.WriteUint64(lval / exp) + fval := lval % exp + if fval == 0 { + return + } + stream.writeByte('.') + for p := precision - 1; p > 0 && fval < pow10[p]; p-- { + stream.writeByte('0') + } + stream.WriteUint64(fval) + for stream.buf[len(stream.buf)-1] == '0' { + stream.buf = stream.buf[:len(stream.buf)-1] + } +} diff --git a/vendor/github.com/json-iterator/go/stream_int.go b/vendor/github.com/json-iterator/go/stream_int.go new file mode 100644 index 0000000000000..d1059ee4c20e3 --- /dev/null +++ b/vendor/github.com/json-iterator/go/stream_int.go @@ -0,0 +1,190 @@ +package jsoniter + +var digits []uint32 + +func init() { + digits = make([]uint32, 1000) + for i := uint32(0); i < 1000; i++ { + digits[i] = (((i / 100) + '0') << 16) + ((((i / 10) % 10) + '0') << 8) + i%10 + '0' + if i < 10 { + digits[i] += 2 << 24 + } else if i < 100 { + digits[i] += 1 << 24 + } + } +} + +func writeFirstBuf(space []byte, v uint32) []byte { + start := v >> 24 + if start == 0 { + space = append(space, byte(v>>16), byte(v>>8)) + } else if start == 1 { + space = append(space, byte(v>>8)) + } + space = append(space, byte(v)) + return space +} + +func writeBuf(buf []byte, v uint32) []byte { + return append(buf, byte(v>>16), byte(v>>8), byte(v)) +} + +// WriteUint8 write uint8 to stream +func (stream *Stream) WriteUint8(val uint8) { + stream.buf = writeFirstBuf(stream.buf, digits[val]) +} + +// WriteInt8 write int8 to stream +func (stream *Stream) WriteInt8(nval int8) { + var val uint8 + if nval < 0 { + val = uint8(-nval) + stream.buf = append(stream.buf, '-') + } else { + val = uint8(nval) + } + stream.buf = writeFirstBuf(stream.buf, digits[val]) +} + +// WriteUint16 write uint16 to stream +func (stream *Stream) WriteUint16(val uint16) { + q1 := val / 1000 + if q1 == 0 { + stream.buf = writeFirstBuf(stream.buf, digits[val]) + return + } + r1 := val - q1*1000 + stream.buf = writeFirstBuf(stream.buf, digits[q1]) + stream.buf = writeBuf(stream.buf, digits[r1]) + return +} + +// WriteInt16 write int16 to stream +func (stream *Stream) WriteInt16(nval int16) { + var val uint16 + if nval < 0 { + val = uint16(-nval) + stream.buf = append(stream.buf, '-') + } else { + val = uint16(nval) + } + stream.WriteUint16(val) +} + +// WriteUint32 write uint32 to stream +func (stream *Stream) WriteUint32(val uint32) { + q1 := val / 1000 + if q1 == 0 { + stream.buf = writeFirstBuf(stream.buf, digits[val]) + return + } + r1 := val - q1*1000 + q2 := q1 / 1000 + if q2 == 0 { + stream.buf = writeFirstBuf(stream.buf, digits[q1]) + stream.buf = writeBuf(stream.buf, digits[r1]) + return + } + r2 := q1 - q2*1000 + q3 := q2 / 1000 + if q3 == 0 { + stream.buf = writeFirstBuf(stream.buf, digits[q2]) + } else { + r3 := q2 - q3*1000 + stream.buf = append(stream.buf, byte(q3+'0')) + stream.buf = writeBuf(stream.buf, digits[r3]) + } + stream.buf = writeBuf(stream.buf, digits[r2]) + stream.buf = writeBuf(stream.buf, digits[r1]) +} + +// WriteInt32 write int32 to stream +func (stream *Stream) WriteInt32(nval int32) { + var val uint32 + if nval < 0 { + val = uint32(-nval) + stream.buf = append(stream.buf, '-') + } else { + val = uint32(nval) + } + stream.WriteUint32(val) +} + +// WriteUint64 write uint64 to stream +func (stream *Stream) WriteUint64(val uint64) { + q1 := val / 1000 + if q1 == 0 { + stream.buf = writeFirstBuf(stream.buf, digits[val]) + return + } + r1 := val - q1*1000 + q2 := q1 / 1000 + if q2 == 0 { + stream.buf = writeFirstBuf(stream.buf, digits[q1]) + stream.buf = writeBuf(stream.buf, digits[r1]) + return + } + r2 := q1 - q2*1000 + q3 := q2 / 1000 + if q3 == 0 { + stream.buf = writeFirstBuf(stream.buf, digits[q2]) + stream.buf = writeBuf(stream.buf, digits[r2]) + stream.buf = writeBuf(stream.buf, digits[r1]) + return + } + r3 := q2 - q3*1000 + q4 := q3 / 1000 + if q4 == 0 { + stream.buf = writeFirstBuf(stream.buf, digits[q3]) + stream.buf = writeBuf(stream.buf, digits[r3]) + stream.buf = writeBuf(stream.buf, digits[r2]) + stream.buf = writeBuf(stream.buf, digits[r1]) + return + } + r4 := q3 - q4*1000 + q5 := q4 / 1000 + if q5 == 0 { + stream.buf = writeFirstBuf(stream.buf, digits[q4]) + stream.buf = writeBuf(stream.buf, digits[r4]) + stream.buf = writeBuf(stream.buf, digits[r3]) + stream.buf = writeBuf(stream.buf, digits[r2]) + stream.buf = writeBuf(stream.buf, digits[r1]) + return + } + r5 := q4 - q5*1000 + q6 := q5 / 1000 + if q6 == 0 { + stream.buf = writeFirstBuf(stream.buf, digits[q5]) + } else { + stream.buf = writeFirstBuf(stream.buf, digits[q6]) + r6 := q5 - q6*1000 + stream.buf = writeBuf(stream.buf, digits[r6]) + } + stream.buf = writeBuf(stream.buf, digits[r5]) + stream.buf = writeBuf(stream.buf, digits[r4]) + stream.buf = writeBuf(stream.buf, digits[r3]) + stream.buf = writeBuf(stream.buf, digits[r2]) + stream.buf = writeBuf(stream.buf, digits[r1]) +} + +// WriteInt64 write int64 to stream +func (stream *Stream) WriteInt64(nval int64) { + var val uint64 + if nval < 0 { + val = uint64(-nval) + stream.buf = append(stream.buf, '-') + } else { + val = uint64(nval) + } + stream.WriteUint64(val) +} + +// WriteInt write int to stream +func (stream *Stream) WriteInt(val int) { + stream.WriteInt64(int64(val)) +} + +// WriteUint write uint to stream +func (stream *Stream) WriteUint(val uint) { + stream.WriteUint64(uint64(val)) +} diff --git a/vendor/github.com/json-iterator/go/stream_str.go b/vendor/github.com/json-iterator/go/stream_str.go new file mode 100644 index 0000000000000..54c2ba0b3a2d9 --- /dev/null +++ b/vendor/github.com/json-iterator/go/stream_str.go @@ -0,0 +1,372 @@ +package jsoniter + +import ( + "unicode/utf8" +) + +// htmlSafeSet holds the value true if the ASCII character with the given +// array position can be safely represented inside a JSON string, embedded +// inside of HTML