wenzuochao 6 years ago
parent
commit
69663be27b
88 changed files with 10988 additions and 8647 deletions
  1. 18 35
      Gopkg.lock
  2. 11 13
      Gopkg.toml
  3. 0 130
      vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/auth.go
  4. 0 973
      vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/bucket.go
  5. 0 805
      vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/client.go
  6. 0 128
      vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/conf.go
  7. 0 730
      vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/conn.go
  8. 0 146
      vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/const.go
  9. 0 123
      vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/crc.go
  10. 0 568
      vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/download.go
  11. 0 94
      vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/error.go
  12. 0 28
      vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/limit_reader_1_6.go
  13. 0 91
      vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/limit_reader_1_7.go
  14. 0 257
      vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/livechannel.go
  15. 0 245
      vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/mime.go
  16. 0 68
      vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/model.go
  17. 0 468
      vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/multicopy.go
  18. 0 290
      vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/multipart.go
  19. 0 433
      vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/option.go
  20. 0 112
      vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/progress.go
  21. 0 26
      vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/transport_1_6.go
  22. 0 28
      vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/transport_1_7.go
  23. 0 566
      vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/type.go
  24. 0 526
      vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/upload.go
  25. 0 265
      vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/utils.go
  26. 1 1
      vendor/github.com/jmespath/go-jmespath/.gitignore
  27. 1 1
      vendor/github.com/jmespath/go-jmespath/Makefile
  28. 0 37
      vendor/github.com/jmespath/go-jmespath/api.go
  29. 63 65
      vendor/github.com/jmespath/go-jmespath/functions.go
  30. 2 2
      vendor/github.com/jmespath/go-jmespath/parser.go
  31. 0 4
      vendor/github.com/json-iterator/go/README.md
  32. 1 1
      vendor/github.com/json-iterator/go/adapter.go
  33. 4 0
      vendor/github.com/json-iterator/go/any.go
  34. 11 0
      vendor/github.com/json-iterator/go/go.mod
  35. 14 0
      vendor/github.com/json-iterator/go/go.sum
  36. 6 14
      vendor/github.com/json-iterator/go/iter_float.go
  37. 13 12
      vendor/github.com/json-iterator/go/iter_skip.go
  38. 12 2
      vendor/github.com/json-iterator/go/iter_skip_strict.go
  39. 1 1
      vendor/github.com/json-iterator/go/reflect_extension.go
  40. 14 2
      vendor/github.com/json-iterator/go/reflect_map.go
  41. 1 2
      vendor/github.com/json-iterator/go/reflect_marshaler.go
  42. 8 6
      vendor/github.com/json-iterator/go/reflect_native.go
  43. 1 1
      vendor/github.com/json-iterator/go/reflect_struct_decoder.go
  44. 17 0
      vendor/github.com/json-iterator/go/stream_float.go
  45. 0 23
      vendor/github.com/satori/go.uuid/.travis.yml
  46. 0 20
      vendor/github.com/satori/go.uuid/LICENSE
  47. 0 65
      vendor/github.com/satori/go.uuid/README.md
  48. 0 206
      vendor/github.com/satori/go.uuid/codec.go
  49. 0 239
      vendor/github.com/satori/go.uuid/generator.go
  50. 0 78
      vendor/github.com/satori/go.uuid/sql.go
  51. 0 161
      vendor/github.com/satori/go.uuid/uuid.go
  52. 82 0
      vendor/github.com/stretchr/testify/assert/assertion_format.go
  53. 164 0
      vendor/github.com/stretchr/testify/assert/assertion_forward.go
  54. 309 0
      vendor/github.com/stretchr/testify/assert/assertion_order.go
  55. 89 7
      vendor/github.com/stretchr/testify/assert/assertions.go
  56. 0 3
      vendor/golang.org/x/time/AUTHORS
  57. 0 3
      vendor/golang.org/x/time/CONTRIBUTORS
  58. 0 27
      vendor/golang.org/x/time/LICENSE
  59. 0 22
      vendor/golang.org/x/time/PATENTS
  60. 0 374
      vendor/golang.org/x/time/rate/rate.go
  61. 2 0
      vendor/gopkg.in/ini.v1/.travis.yml
  62. 14 6
      vendor/gopkg.in/ini.v1/README.md
  63. 2 0
      vendor/gopkg.in/ini.v1/error.go
  64. 6 6
      vendor/gopkg.in/ini.v1/file.go
  65. 18 14
      vendor/gopkg.in/ini.v1/ini.go
  66. 6 5
      vendor/gopkg.in/ini.v1/key.go
  67. 67 68
      vendor/gopkg.in/ini.v1/parser.go
  68. 2 5
      vendor/gopkg.in/ini.v1/section.go
  69. 67 16
      vendor/gopkg.in/ini.v1/struct.go
  70. 12 0
      vendor/gopkg.in/yaml.v2/.travis.yml
  71. 201 0
      vendor/gopkg.in/yaml.v2/LICENSE
  72. 31 0
      vendor/gopkg.in/yaml.v2/LICENSE.libyaml
  73. 13 0
      vendor/gopkg.in/yaml.v2/NOTICE
  74. 133 0
      vendor/gopkg.in/yaml.v2/README.md
  75. 739 0
      vendor/gopkg.in/yaml.v2/apic.go
  76. 775 0
      vendor/gopkg.in/yaml.v2/decode.go
  77. 1685 0
      vendor/gopkg.in/yaml.v2/emitterc.go
  78. 390 0
      vendor/gopkg.in/yaml.v2/encode.go
  79. 5 0
      vendor/gopkg.in/yaml.v2/go.mod
  80. 1095 0
      vendor/gopkg.in/yaml.v2/parserc.go
  81. 412 0
      vendor/gopkg.in/yaml.v2/readerc.go
  82. 258 0
      vendor/gopkg.in/yaml.v2/resolve.go
  83. 2696 0
      vendor/gopkg.in/yaml.v2/scannerc.go
  84. 113 0
      vendor/gopkg.in/yaml.v2/sorter.go
  85. 26 0
      vendor/gopkg.in/yaml.v2/writerc.go
  86. 466 0
      vendor/gopkg.in/yaml.v2/yaml.go
  87. 738 0
      vendor/gopkg.in/yaml.v2/yamlh.go
  88. 173 0
      vendor/gopkg.in/yaml.v2/yamlprivateh.go

+ 18 - 35
Gopkg.lock

@@ -1,14 +1,6 @@
 # This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
 
 
-[[projects]]
-  digest = "1:a9a98adb2a4181b9e4622eff8b6070646971a18427c265852f3686dbc7112ab1"
-  name = "github.com/aliyun/aliyun-oss-go-sdk"
-  packages = ["oss"]
-  pruneopts = "UT"
-  revision = "86c17b95fcd5db33628a61e492fb4a1a937d5906"
-  version = "1.9.5"
-
 [[projects]]
   digest = "1:ffe9824d294da03b391f44e1ae8281281b4afc1bdaa9588c9097785e3af10cec"
   name = "github.com/davecgh/go-spew"
@@ -26,19 +18,20 @@
   revision = "2da839ab0f4df05a6db5eb277995589dadbd4fb9"
 
 [[projects]]
-  digest = "1:bb81097a5b62634f3e9fec1014657855610c82d19b9a40c17612e32651e35dca"
+  digest = "1:b87714e57a511d88f307aba7d5b63522da12bed0a050889c81272fc50f71100e"
   name = "github.com/jmespath/go-jmespath"
   packages = ["."]
   pruneopts = "UT"
-  revision = "c2b33e84"
+  revision = "3433f3ea46d9f8019119e7dd41274e112a2359a9"
+  version = "0.2.2"
 
 [[projects]]
-  digest = "1:3e551bbb3a7c0ab2a2bf4660e7fcad16db089fdcfbb44b0199e62838038623ea"
+  digest = "1:709cd2a2c29cc9b89732f6c24846bbb9d6270f28ef5ef2128cc73bd0d6d7bff9"
   name = "github.com/json-iterator/go"
   packages = ["."]
   pruneopts = "UT"
-  revision = "1624edc4454b8682399def8740d46db5e4362ba4"
-  version = "v1.1.5"
+  revision = "27518f6661eba504be5a7a9a9f6d9460d892ade3"
+  version = "v1.1.7"
 
 [[projects]]
   digest = "1:33422d238f147d247752996a26574ac48dcf472976eda7f5134015f06bf16563"
@@ -65,46 +58,36 @@
   version = "v1.0.0"
 
 [[projects]]
-  digest = "1:274f67cb6fed9588ea2521ecdac05a6d62a8c51c074c1fccc6a49a40ba80e925"
-  name = "github.com/satori/go.uuid"
-  packages = ["."]
-  pruneopts = "UT"
-  revision = "f58768cc1a7a7e77a3bd49e98cdd21419399b6a3"
-  version = "v1.2.0"
-
-[[projects]]
-  digest = "1:972c2427413d41a1e06ca4897e8528e5a1622894050e2f527b38ddf0f343f759"
+  digest = "1:8548c309c65a85933a625be5e7d52b6ac927ca30c56869fae58123b8a77a75e1"
   name = "github.com/stretchr/testify"
   packages = ["assert"]
   pruneopts = "UT"
-  revision = "ffdc059bfe9ce6a4e144ba849dbedead332c6053"
-  version = "v1.3.0"
+  revision = "221dbe5ed46703ee255b1da0dec05086f5035f62"
+  version = "v1.4.0"
 
 [[projects]]
-  branch = "master"
-  digest = "1:9fdc2b55e8e0fafe4b41884091e51e77344f7dc511c5acedcfd98200003bff90"
-  name = "golang.org/x/time"
-  packages = ["rate"]
+  digest = "1:6c56c50b13fd3cb33b692b264727c1c89198274f5dcabaa077e3b2472037e0f9"
+  name = "gopkg.in/ini.v1"
+  packages = ["."]
   pruneopts = "UT"
-  revision = "9d24e82272b4f38b78bc8cff74fa936d31ccd8ef"
+  revision = "d4cae42d398bc0095297fc3315669590d29166ea"
+  version = "v1.46.0"
 
 [[projects]]
-  digest = "1:d37c61a335d13bc49b3f90e9e13c8686e4548839b69c58549e727afb2245c454"
-  name = "gopkg.in/ini.v1"
+  digest = "1:4d2e5a73dc1500038e504a8d78b986630e3626dc027bc030ba5c75da257cdb96"
+  name = "gopkg.in/yaml.v2"
   packages = ["."]
   pruneopts = "UT"
-  revision = "c85607071cf08ca1adaf48319cd1aa322e81d8c1"
-  version = "v1.42.0"
+  revision = "51d6538a90f86fe93ac480b35f37b2be17fef232"
+  version = "v2.2.2"
 
 [solve-meta]
   analyzer-name = "dep"
   analyzer-version = 1
   input-imports = [
-    "github.com/aliyun/aliyun-oss-go-sdk/oss",
     "github.com/goji/httpauth",
     "github.com/jmespath/go-jmespath",
     "github.com/json-iterator/go",
-    "github.com/satori/go.uuid",
     "github.com/stretchr/testify/assert",
     "gopkg.in/ini.v1",
   ]

+ 11 - 13
Gopkg.toml

@@ -1,6 +1,6 @@
 # Gopkg.toml example
 #
-# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
+# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html
 # for detailed Gopkg.toml documentation.
 #
 # required = ["github.com/user/thing/cmd/thing"]
@@ -24,28 +24,26 @@
 #   go-tests = true
 #   unused-packages = true
 
-#ignored = [
-#  "golang.org/x/sys/unix",
-#  "golang.org/x/sys/windows",
-#  "golang.org/x/crypto/ssh/terminal",
-#]
+
+[[constraint]]
+  branch = "master"
+  name = "github.com/goji/httpauth"
 
 [[constraint]]
   name = "github.com/jmespath/go-jmespath"
-  revision = "c2b33e84"
-  #version = "0.2.2"
+  version = "0.2.2"
 
 [[constraint]]
   name = "github.com/json-iterator/go"
-  version = "v1.1.5"
+  version = "1.1.7"
 
 [[constraint]]
-  name = "github.com/satori/go.uuid"
-  version = "1.1.0"
+  name = "github.com/stretchr/testify"
+  version = "1.4.0"
 
 [[constraint]]
-  name = "github.com/stretchr/testify"
-  version = "v1.3.0"
+  name = "gopkg.in/ini.v1"
+  version = "1.46.0"
 
 [prune]
   go-tests = true

+ 0 - 130
vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/auth.go

@@ -1,130 +0,0 @@
-package oss
-
-import (
-	"bytes"
-	"crypto/hmac"
-	"crypto/sha1"
-	"encoding/base64"
-	"fmt"
-	"hash"
-	"io"
-	"net/http"
-	"sort"
-	"strconv"
-	"strings"
-)
-
-// headerSorter defines the key-value structure for storing the sorted data in signHeader.
-type headerSorter struct {
-	Keys []string
-	Vals []string
-}
-
-// signHeader signs the header and sets it as the authorization header.
-func (conn Conn) signHeader(req *http.Request, canonicalizedResource string) {
-	// Get the final authorization string
-	authorizationStr := "OSS " + conn.config.AccessKeyID + ":" + conn.getSignedStr(req, canonicalizedResource)
-
-	// Give the parameter "Authorization" value
-	req.Header.Set(HTTPHeaderAuthorization, authorizationStr)
-}
-
-func (conn Conn) getSignedStr(req *http.Request, canonicalizedResource string) string {
-	// Find out the "x-oss-"'s address in header of the request
-	temp := make(map[string]string)
-
-	for k, v := range req.Header {
-		if strings.HasPrefix(strings.ToLower(k), "x-oss-") {
-			temp[strings.ToLower(k)] = v[0]
-		}
-	}
-	hs := newHeaderSorter(temp)
-
-	// Sort the temp by the ascending order
-	hs.Sort()
-
-	// Get the canonicalizedOSSHeaders
-	canonicalizedOSSHeaders := ""
-	for i := range hs.Keys {
-		canonicalizedOSSHeaders += hs.Keys[i] + ":" + hs.Vals[i] + "\n"
-	}
-
-	// Give other parameters values
-	// when sign URL, date is expires
-	date := req.Header.Get(HTTPHeaderDate)
-	contentType := req.Header.Get(HTTPHeaderContentType)
-	contentMd5 := req.Header.Get(HTTPHeaderContentMD5)
-
-	signStr := req.Method + "\n" + contentMd5 + "\n" + contentType + "\n" + date + "\n" + canonicalizedOSSHeaders + canonicalizedResource
-
-	conn.config.WriteLog(Debug, "[Req:%p]signStr:%s.\n", req, signStr)
-
-	h := hmac.New(func() hash.Hash { return sha1.New() }, []byte(conn.config.AccessKeySecret))
-	io.WriteString(h, signStr)
-	signedStr := base64.StdEncoding.EncodeToString(h.Sum(nil))
-
-	return signedStr
-}
-
-func (conn Conn) getRtmpSignedStr(bucketName, channelName, playlistName string, expiration int64, params map[string]interface{}) string {
-	if params[HTTPParamAccessKeyID] == nil {
-		return ""
-	}
-
-	canonResource := fmt.Sprintf("/%s/%s", bucketName, channelName)
-	canonParamsKeys := []string{}
-	for key := range params {
-		if key != HTTPParamAccessKeyID && key != HTTPParamSignature && key != HTTPParamExpires && key != HTTPParamSecurityToken {
-			canonParamsKeys = append(canonParamsKeys, key)
-		}
-	}
-
-	sort.Strings(canonParamsKeys)
-	canonParamsStr := ""
-	for _, key := range canonParamsKeys {
-		canonParamsStr = fmt.Sprintf("%s%s:%s\n", canonParamsStr, key, params[key].(string))
-	}
-
-	expireStr := strconv.FormatInt(expiration, 10)
-	signStr := expireStr + "\n" + canonParamsStr + canonResource
-
-	h := hmac.New(func() hash.Hash { return sha1.New() }, []byte(conn.config.AccessKeySecret))
-	io.WriteString(h, signStr)
-	signedStr := base64.StdEncoding.EncodeToString(h.Sum(nil))
-	return signedStr
-}
-
-// newHeaderSorter is an additional function for function SignHeader.
-func newHeaderSorter(m map[string]string) *headerSorter {
-	hs := &headerSorter{
-		Keys: make([]string, 0, len(m)),
-		Vals: make([]string, 0, len(m)),
-	}
-
-	for k, v := range m {
-		hs.Keys = append(hs.Keys, k)
-		hs.Vals = append(hs.Vals, v)
-	}
-	return hs
-}
-
-// Sort is an additional function for function SignHeader.
-func (hs *headerSorter) Sort() {
-	sort.Sort(hs)
-}
-
-// Len is an additional function for function SignHeader.
-func (hs *headerSorter) Len() int {
-	return len(hs.Vals)
-}
-
-// Less is an additional function for function SignHeader.
-func (hs *headerSorter) Less(i, j int) bool {
-	return bytes.Compare([]byte(hs.Keys[i]), []byte(hs.Keys[j])) < 0
-}
-
-// Swap is an additional function for function SignHeader.
-func (hs *headerSorter) Swap(i, j int) {
-	hs.Vals[i], hs.Vals[j] = hs.Vals[j], hs.Vals[i]
-	hs.Keys[i], hs.Keys[j] = hs.Keys[j], hs.Keys[i]
-}

+ 0 - 973
vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/bucket.go

@@ -1,973 +0,0 @@
-package oss
-
-import (
-	"bytes"
-	"crypto/md5"
-	"encoding/base64"
-	"encoding/xml"
-	"fmt"
-	"hash"
-	"hash/crc64"
-	"io"
-	"net/http"
-	"net/url"
-	"os"
-	"strconv"
-	"strings"
-	"time"
-)
-
-// Bucket implements the operations of object.
-type Bucket struct {
-	Client     Client
-	BucketName string
-}
-
-// PutObject creates a new object and it will overwrite the original one if it exists already.
-//
-// objectKey    the object key in UTF-8 encoding. The length must be between 1 and 1023, and cannot start with "/" or "\".
-// reader    io.Reader instance for reading the data for uploading
-// options    the options for uploading the object. The valid options here are CacheControl, ContentDisposition, ContentEncoding
-//            Expires, ServerSideEncryption, ObjectACL and Meta. Refer to the link below for more details.
-//            https://help.aliyun.com/document_detail/oss/api-reference/object/PutObject.html
-//
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (bucket Bucket) PutObject(objectKey string, reader io.Reader, options ...Option) error {
-	opts := addContentType(options, objectKey)
-
-	request := &PutObjectRequest{
-		ObjectKey: objectKey,
-		Reader:    reader,
-	}
-	resp, err := bucket.DoPutObject(request, opts)
-	if err != nil {
-		return err
-	}
-	defer resp.Body.Close()
-
-	return err
-}
-
-// PutObjectFromFile creates a new object from the local file.
-//
-// objectKey    object key.
-// filePath    the local file path to upload.
-// options    the options for uploading the object. Refer to the parameter options in PutObject for more details.
-//
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (bucket Bucket) PutObjectFromFile(objectKey, filePath string, options ...Option) error {
-	fd, err := os.Open(filePath)
-	if err != nil {
-		return err
-	}
-	defer fd.Close()
-
-	opts := addContentType(options, filePath, objectKey)
-
-	request := &PutObjectRequest{
-		ObjectKey: objectKey,
-		Reader:    fd,
-	}
-	resp, err := bucket.DoPutObject(request, opts)
-	if err != nil {
-		return err
-	}
-	defer resp.Body.Close()
-
-	return err
-}
-
-// DoPutObject does the actual upload work.
-//
-// request    the request instance for uploading an object.
-// options    the options for uploading an object.
-//
-// Response    the response from OSS.
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (bucket Bucket) DoPutObject(request *PutObjectRequest, options []Option) (*Response, error) {
-	isOptSet, _, _ := isOptionSet(options, HTTPHeaderContentType)
-	if !isOptSet {
-		options = addContentType(options, request.ObjectKey)
-	}
-
-	listener := getProgressListener(options)
-
-	params := map[string]interface{}{}
-	resp, err := bucket.do("PUT", request.ObjectKey, params, options, request.Reader, listener)
-	if err != nil {
-		return nil, err
-	}
-
-	if bucket.getConfig().IsEnableCRC {
-		err = checkCRC(resp, "DoPutObject")
-		if err != nil {
-			return resp, err
-		}
-	}
-
-	err = checkRespCode(resp.StatusCode, []int{http.StatusOK})
-
-	return resp, err
-}
-
-// GetObject downloads the object.
-//
-// objectKey    the object key.
-// options    the options for downloading the object. The valid values are: Range, IfModifiedSince, IfUnmodifiedSince, IfMatch,
-//            IfNoneMatch, AcceptEncoding. For more details, please check out:
-//            https://help.aliyun.com/document_detail/oss/api-reference/object/GetObject.html
-//
-// io.ReadCloser    reader instance for reading data from response. It must be called close() after the usage and only valid when error is nil.
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (bucket Bucket) GetObject(objectKey string, options ...Option) (io.ReadCloser, error) {
-	result, err := bucket.DoGetObject(&GetObjectRequest{objectKey}, options)
-	if err != nil {
-		return nil, err
-	}
-
-	return result.Response, nil
-}
-
-// GetObjectToFile downloads the data to a local file.
-//
-// objectKey    the object key to download.
-// filePath    the local file to store the object data.
-// options    the options for downloading the object. Refer to the parameter options in method GetObject for more details.
-//
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (bucket Bucket) GetObjectToFile(objectKey, filePath string, options ...Option) error {
-	tempFilePath := filePath + TempFileSuffix
-
-	// Calls the API to actually download the object. Returns the result instance.
-	result, err := bucket.DoGetObject(&GetObjectRequest{objectKey}, options)
-	if err != nil {
-		return err
-	}
-	defer result.Response.Close()
-
-	// If the local file does not exist, create a new one. If it exists, overwrite it.
-	fd, err := os.OpenFile(tempFilePath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, FilePermMode)
-	if err != nil {
-		return err
-	}
-
-	// Copy the data to the local file path.
-	_, err = io.Copy(fd, result.Response.Body)
-	fd.Close()
-	if err != nil {
-		return err
-	}
-
-	// Compares the CRC value
-	hasRange, _, _ := isOptionSet(options, HTTPHeaderRange)
-	encodeOpt, _ := findOption(options, HTTPHeaderAcceptEncoding, nil)
-	acceptEncoding := ""
-	if encodeOpt != nil {
-		acceptEncoding = encodeOpt.(string)
-	}
-	if bucket.getConfig().IsEnableCRC && !hasRange && acceptEncoding != "gzip" {
-		result.Response.ClientCRC = result.ClientCRC.Sum64()
-		err = checkCRC(result.Response, "GetObjectToFile")
-		if err != nil {
-			os.Remove(tempFilePath)
-			return err
-		}
-	}
-
-	return os.Rename(tempFilePath, filePath)
-}
-
-// DoGetObject is the actual API that gets the object. It's the internal function called by other public APIs.
-//
-// request    the request to download the object.
-// options    the options for downloading the file. Checks out the parameter options in method GetObject.
-//
-// GetObjectResult    the result instance of getting the object.
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (bucket Bucket) DoGetObject(request *GetObjectRequest, options []Option) (*GetObjectResult, error) {
-	params, _ := getRawParams(options)
-	resp, err := bucket.do("GET", request.ObjectKey, params, options, nil, nil)
-	if err != nil {
-		return nil, err
-	}
-
-	result := &GetObjectResult{
-		Response: resp,
-	}
-
-	// CRC
-	var crcCalc hash.Hash64
-	hasRange, _, _ := isOptionSet(options, HTTPHeaderRange)
-	if bucket.getConfig().IsEnableCRC && !hasRange {
-		crcCalc = crc64.New(crcTable())
-		result.ServerCRC = resp.ServerCRC
-		result.ClientCRC = crcCalc
-	}
-
-	// Progress
-	listener := getProgressListener(options)
-
-	contentLen, _ := strconv.ParseInt(resp.Headers.Get(HTTPHeaderContentLength), 10, 64)
-	resp.Body = TeeReader(resp.Body, crcCalc, contentLen, listener, nil)
-
-	return result, nil
-}
-
-// CopyObject copies the object inside the bucket.
-//
-// srcObjectKey    the source object to copy.
-// destObjectKey    the target object to copy.
-// options    options for copying an object. You can specify the conditions of copy. The valid conditions are CopySourceIfMatch,
-//            CopySourceIfNoneMatch, CopySourceIfModifiedSince, CopySourceIfUnmodifiedSince, MetadataDirective.
-//            Also you can specify the target object's attributes, such as CacheControl, ContentDisposition, ContentEncoding, Expires,
-//            ServerSideEncryption, ObjectACL, Meta. Refer to the link below for more details :
-//            https://help.aliyun.com/document_detail/oss/api-reference/object/CopyObject.html
-//
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (bucket Bucket) CopyObject(srcObjectKey, destObjectKey string, options ...Option) (CopyObjectResult, error) {
-	var out CopyObjectResult
-	options = append(options, CopySource(bucket.BucketName, url.QueryEscape(srcObjectKey)))
-	params := map[string]interface{}{}
-	resp, err := bucket.do("PUT", destObjectKey, params, options, nil, nil)
-	if err != nil {
-		return out, err
-	}
-	defer resp.Body.Close()
-
-	err = xmlUnmarshal(resp.Body, &out)
-	return out, err
-}
-
-// CopyObjectTo copies the object to another bucket.
-//
-// srcObjectKey    source object key. The source bucket is Bucket.BucketName .
-// destBucketName    target bucket name.
-// destObjectKey    target object name.
-// options    copy options, check out parameter options in function CopyObject for more details.
-//
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (bucket Bucket) CopyObjectTo(destBucketName, destObjectKey, srcObjectKey string, options ...Option) (CopyObjectResult, error) {
-	return bucket.copy(srcObjectKey, destBucketName, destObjectKey, options...)
-}
-
-//
-// CopyObjectFrom copies the object to another bucket.
-//
-// srcBucketName    source bucket name.
-// srcObjectKey    source object name.
-// destObjectKey    target object name. The target bucket name is Bucket.BucketName.
-// options    copy options. Check out parameter options in function CopyObject.
-//
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (bucket Bucket) CopyObjectFrom(srcBucketName, srcObjectKey, destObjectKey string, options ...Option) (CopyObjectResult, error) {
-	destBucketName := bucket.BucketName
-	var out CopyObjectResult
-	srcBucket, err := bucket.Client.Bucket(srcBucketName)
-	if err != nil {
-		return out, err
-	}
-
-	return srcBucket.copy(srcObjectKey, destBucketName, destObjectKey, options...)
-}
-
-func (bucket Bucket) copy(srcObjectKey, destBucketName, destObjectKey string, options ...Option) (CopyObjectResult, error) {
-	var out CopyObjectResult
-	options = append(options, CopySource(bucket.BucketName, url.QueryEscape(srcObjectKey)))
-	headers := make(map[string]string)
-	err := handleOptions(headers, options)
-	if err != nil {
-		return out, err
-	}
-	params := map[string]interface{}{}
-	resp, err := bucket.Client.Conn.Do("PUT", destBucketName, destObjectKey, params, headers, nil, 0, nil)
-	if err != nil {
-		return out, err
-	}
-	defer resp.Body.Close()
-
-	err = xmlUnmarshal(resp.Body, &out)
-	return out, err
-}
-
-// AppendObject uploads the data in the way of appending an existing or new object.
-//
-// AppendObject the parameter appendPosition specifies which postion (in the target object) to append. For the first append (to a non-existing file),
-// the appendPosition should be 0. The appendPosition in the subsequent calls will be the current object length.
-// For example, the first appendObject's appendPosition is 0 and it uploaded 65536 bytes data, then the second call's position is 65536.
-// The response header x-oss-next-append-position after each successful request also specifies the next call's append position (so the caller need not to maintain this information).
-//
-// objectKey    the target object to append to.
-// reader    io.Reader. The read instance for reading the data to append.
-// appendPosition    the start position to append.
-// destObjectProperties    the options for the first appending, such as CacheControl, ContentDisposition, ContentEncoding,
-//                         Expires, ServerSideEncryption, ObjectACL.
-//
-// int64    the next append position, it's valid when error is nil.
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (bucket Bucket) AppendObject(objectKey string, reader io.Reader, appendPosition int64, options ...Option) (int64, error) {
-	request := &AppendObjectRequest{
-		ObjectKey: objectKey,
-		Reader:    reader,
-		Position:  appendPosition,
-	}
-
-	result, err := bucket.DoAppendObject(request, options)
-	if err != nil {
-		return appendPosition, err
-	}
-
-	return result.NextPosition, err
-}
-
-// DoAppendObject is the actual API that does the object append.
-//
-// request    the request object for appending object.
-// options    the options for appending object.
-//
-// AppendObjectResult    the result object for appending object.
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (bucket Bucket) DoAppendObject(request *AppendObjectRequest, options []Option) (*AppendObjectResult, error) {
-	params := map[string]interface{}{}
-	params["append"] = nil
-	params["position"] = strconv.FormatInt(request.Position, 10)
-	headers := make(map[string]string)
-
-	opts := addContentType(options, request.ObjectKey)
-	handleOptions(headers, opts)
-
-	var initCRC uint64
-	isCRCSet, initCRCOpt, _ := isOptionSet(options, initCRC64)
-	if isCRCSet {
-		initCRC = initCRCOpt.(uint64)
-	}
-
-	listener := getProgressListener(options)
-
-	handleOptions(headers, opts)
-	resp, err := bucket.Client.Conn.Do("POST", bucket.BucketName, request.ObjectKey, params, headers,
-		request.Reader, initCRC, listener)
-	if err != nil {
-		return nil, err
-	}
-	defer resp.Body.Close()
-
-	nextPosition, _ := strconv.ParseInt(resp.Headers.Get(HTTPHeaderOssNextAppendPosition), 10, 64)
-	result := &AppendObjectResult{
-		NextPosition: nextPosition,
-		CRC:          resp.ServerCRC,
-	}
-
-	if bucket.getConfig().IsEnableCRC && isCRCSet {
-		err = checkCRC(resp, "AppendObject")
-		if err != nil {
-			return result, err
-		}
-	}
-
-	return result, nil
-}
-
-// DeleteObject deletes the object.
-//
-// objectKey    the object key to delete.
-//
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (bucket Bucket) DeleteObject(objectKey string) error {
-	params := map[string]interface{}{}
-	resp, err := bucket.do("DELETE", objectKey, params, nil, nil, nil)
-	if err != nil {
-		return err
-	}
-	defer resp.Body.Close()
-	return checkRespCode(resp.StatusCode, []int{http.StatusNoContent})
-}
-
-// DeleteObjects deletes multiple objects.
-//
-// objectKeys    the object keys to delete.
-// options    the options for deleting objects.
-//            Supported option is DeleteObjectsQuiet which means it will not return error even deletion failed (not recommended). By default it's not used.
-//
-// DeleteObjectsResult    the result object.
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (bucket Bucket) DeleteObjects(objectKeys []string, options ...Option) (DeleteObjectsResult, error) {
-	out := DeleteObjectsResult{}
-	dxml := deleteXML{}
-	for _, key := range objectKeys {
-		dxml.Objects = append(dxml.Objects, DeleteObject{Key: key})
-	}
-	isQuiet, _ := findOption(options, deleteObjectsQuiet, false)
-	dxml.Quiet = isQuiet.(bool)
-
-	bs, err := xml.Marshal(dxml)
-	if err != nil {
-		return out, err
-	}
-	buffer := new(bytes.Buffer)
-	buffer.Write(bs)
-
-	contentType := http.DetectContentType(buffer.Bytes())
-	options = append(options, ContentType(contentType))
-	sum := md5.Sum(bs)
-	b64 := base64.StdEncoding.EncodeToString(sum[:])
-	options = append(options, ContentMD5(b64))
-
-	params := map[string]interface{}{}
-	params["delete"] = nil
-	params["encoding-type"] = "url"
-
-	resp, err := bucket.do("POST", "", params, options, buffer, nil)
-	if err != nil {
-		return out, err
-	}
-	defer resp.Body.Close()
-
-	if !dxml.Quiet {
-		if err = xmlUnmarshal(resp.Body, &out); err == nil {
-			err = decodeDeleteObjectsResult(&out)
-		}
-	}
-	return out, err
-}
-
-// IsObjectExist checks if the object exists.
-//
-// bool    flag of object's existence (true:exists; false:non-exist) when error is nil.
-//
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (bucket Bucket) IsObjectExist(objectKey string) (bool, error) {
-	_, err := bucket.GetObjectMeta(objectKey)
-	if err == nil {
-		return true, nil
-	}
-
-	switch err.(type) {
-	case ServiceError:
-		if err.(ServiceError).StatusCode == 404 {
-			return false, nil
-		}
-	}
-
-	return false, err
-}
-
-// ListObjects lists the objects under the current bucket.
-//
-// options    it contains all the filters for listing objects.
-//            It could specify a prefix filter on object keys,  the max keys count to return and the object key marker and the delimiter for grouping object names.
-//            The key marker means the returned objects' key must be greater than it in lexicographic order.
-//
-//            For example, if the bucket has 8 objects, my-object-1, my-object-11, my-object-2, my-object-21,
-//            my-object-22, my-object-3, my-object-31, my-object-32. If the prefix is my-object-2 (no other filters), then it returns
-//            my-object-2, my-object-21, my-object-22 three objects. If the marker is my-object-22 (no other filters), then it returns
-//            my-object-3, my-object-31, my-object-32 three objects. If the max keys is 5, then it returns 5 objects.
-//            The three filters could be used together to achieve filter and paging functionality.
-//            If the prefix is the folder name, then it could list all files under this folder (including the files under its subfolders).
-//            But if the delimiter is specified with '/', then it only returns that folder's files (no subfolder's files). The direct subfolders are in the commonPrefixes properties.
-//            For example, if the bucket has three objects fun/test.jpg, fun/movie/001.avi, fun/movie/007.avi. And if the prefix is "fun/", then it returns all three objects.
-//            But if the delimiter is '/', then only "fun/test.jpg" is returned as files and fun/movie/ is returned as common prefix.
-//
-//            For common usage scenario, check out sample/list_object.go.
-//
-// ListObjectsResponse    the return value after operation succeeds (only valid when error is nil).
-//
-func (bucket Bucket) ListObjects(options ...Option) (ListObjectsResult, error) {
-	var out ListObjectsResult
-
-	options = append(options, EncodingType("url"))
-	params, err := getRawParams(options)
-	if err != nil {
-		return out, err
-	}
-
-	resp, err := bucket.do("GET", "", params, options, nil, nil)
-	if err != nil {
-		return out, err
-	}
-	defer resp.Body.Close()
-
-	err = xmlUnmarshal(resp.Body, &out)
-	if err != nil {
-		return out, err
-	}
-
-	err = decodeListObjectsResult(&out)
-	return out, err
-}
-
-// SetObjectMeta sets the metadata of the Object.
-//
-// objectKey    object
-// options    options for setting the metadata. The valid options are CacheControl, ContentDisposition, ContentEncoding, Expires,
-//            ServerSideEncryption, and custom metadata.
-//
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (bucket Bucket) SetObjectMeta(objectKey string, options ...Option) error {
-	options = append(options, MetadataDirective(MetaReplace))
-	_, err := bucket.CopyObject(objectKey, objectKey, options...)
-	return err
-}
-
-// GetObjectDetailedMeta gets the object's detailed metadata
-//
-// objectKey    object key.
-// options    the constraints of the object. Only when the object meets the requirements this method will return the metadata. Otherwise returns error. Valid options are IfModifiedSince, IfUnmodifiedSince,
-//            IfMatch, IfNoneMatch. For more details check out https://help.aliyun.com/document_detail/oss/api-reference/object/HeadObject.html
-//
-// http.Header    object meta when error is nil.
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (bucket Bucket) GetObjectDetailedMeta(objectKey string, options ...Option) (http.Header, error) {
-	params := map[string]interface{}{}
-	resp, err := bucket.do("HEAD", objectKey, params, options, nil, nil)
-	if err != nil {
-		return nil, err
-	}
-	defer resp.Body.Close()
-
-	return resp.Headers, nil
-}
-
-// GetObjectMeta gets object metadata.
-//
-// GetObjectMeta is more lightweight than GetObjectDetailedMeta as it only returns basic metadata including ETag
-// size, LastModified. The size information is in the HTTP header Content-Length.
-//
-// objectKey    object key
-//
-// http.Header    the object's metadata, valid when error is nil.
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (bucket Bucket) GetObjectMeta(objectKey string, options ...Option) (http.Header, error) {
-	params := map[string]interface{}{}
-	params["objectMeta"] = nil
-	//resp, err := bucket.do("GET", objectKey, "?objectMeta", "", nil, nil, nil)
-	resp, err := bucket.do("HEAD", objectKey, params, options, nil, nil)
-	if err != nil {
-		return nil, err
-	}
-	defer resp.Body.Close()
-
-	return resp.Headers, nil
-}
-
-// SetObjectACL updates the object's ACL.
-//
-// Only the bucket's owner could update object's ACL which priority is higher than bucket's ACL.
-// For example, if the bucket ACL is private and object's ACL is public-read-write.
-// Then object's ACL is used and it means all users could read or write that object.
-// When the object's ACL is not set, then bucket's ACL is used as the object's ACL.
-//
-// Object read operations include GetObject, HeadObject, CopyObject and UploadPartCopy on the source object;
-// Object write operations include PutObject, PostObject, AppendObject, DeleteObject, DeleteMultipleObjects,
-// CompleteMultipartUpload and CopyObject on target object.
-//
-// objectKey    the target object key (to set the ACL on)
-// objectAcl    object ACL. Valid options are PrivateACL, PublicReadACL, PublicReadWriteACL.
-//
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (bucket Bucket) SetObjectACL(objectKey string, objectACL ACLType) error {
-	options := []Option{ObjectACL(objectACL)}
-	params := map[string]interface{}{}
-	params["acl"] = nil
-	resp, err := bucket.do("PUT", objectKey, params, options, nil, nil)
-	if err != nil {
-		return err
-	}
-	defer resp.Body.Close()
-	return checkRespCode(resp.StatusCode, []int{http.StatusOK})
-}
-
-// GetObjectACL gets object's ACL
-//
-// objectKey    the object to get ACL from.
-//
-// GetObjectACLResult    the result object when error is nil. GetObjectACLResult.Acl is the object ACL.
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (bucket Bucket) GetObjectACL(objectKey string) (GetObjectACLResult, error) {
-	var out GetObjectACLResult
-	params := map[string]interface{}{}
-	params["acl"] = nil
-	resp, err := bucket.do("GET", objectKey, params, nil, nil, nil)
-	if err != nil {
-		return out, err
-	}
-	defer resp.Body.Close()
-
-	err = xmlUnmarshal(resp.Body, &out)
-	return out, err
-}
-
-// PutSymlink creates a symlink (to point to an existing object)
-//
-// Symlink cannot point to another symlink.
-// When creating a symlink, it does not check the existence of the target file, and does not check if the target file is symlink.
-// Neither it checks the caller's permission on the target file. All these checks are deferred to the actual GetObject call via this symlink.
-// If trying to add an existing file, as long as the caller has the write permission, the existing one will be overwritten.
-// If the x-oss-meta- is specified, it will be added as the metadata of the symlink file.
-//
-// symObjectKey    the symlink object's key.
-// targetObjectKey    the target object key to point to.
-//
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (bucket Bucket) PutSymlink(symObjectKey string, targetObjectKey string, options ...Option) error {
-	options = append(options, symlinkTarget(url.QueryEscape(targetObjectKey)))
-	params := map[string]interface{}{}
-	params["symlink"] = nil
-	resp, err := bucket.do("PUT", symObjectKey, params, options, nil, nil)
-	if err != nil {
-		return err
-	}
-	defer resp.Body.Close()
-	return checkRespCode(resp.StatusCode, []int{http.StatusOK})
-}
-
-// GetSymlink gets the symlink object with the specified key.
-// If the symlink object does not exist, returns 404.
-//
-// objectKey    the symlink object's key.
-//
-// error    it's nil if no error, otherwise it's an error object.
-//          When error is nil, the target file key is in the X-Oss-Symlink-Target header of the returned object.
-//
-func (bucket Bucket) GetSymlink(objectKey string) (http.Header, error) {
-	params := map[string]interface{}{}
-	params["symlink"] = nil
-	resp, err := bucket.do("GET", objectKey, params, nil, nil, nil)
-	if err != nil {
-		return nil, err
-	}
-	defer resp.Body.Close()
-
-	targetObjectKey := resp.Headers.Get(HTTPHeaderOssSymlinkTarget)
-	targetObjectKey, err = url.QueryUnescape(targetObjectKey)
-	if err != nil {
-		return resp.Headers, err
-	}
-	resp.Headers.Set(HTTPHeaderOssSymlinkTarget, targetObjectKey)
-	return resp.Headers, err
-}
-
-// RestoreObject restores the object from the archive storage.
-//
-// An archive object is in cold status by default and it cannot be accessed.
-// When restore is called on the cold object, it will become available for access after some time.
-// If multiple restores are called on the same file when the object is being restored, server side does nothing for additional calls but returns success.
-// By default, the restored object is available for access for one day. After that it will be unavailable again.
-// But if another RestoreObject are called after the file is restored, then it will extend one day's access time of that object, up to 7 days.
-//
-// objectKey    object key to restore.
-//
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (bucket Bucket) RestoreObject(objectKey string) error {
-	params := map[string]interface{}{}
-	params["restore"] = nil
-	resp, err := bucket.do("POST", objectKey, params, nil, nil, nil)
-	if err != nil {
-		return err
-	}
-	defer resp.Body.Close()
-	return checkRespCode(resp.StatusCode, []int{http.StatusOK, http.StatusAccepted})
-}
-
-// SignURL signs the URL. Users could access the object directly with this URL without getting the AK.
-//
-// objectKey    the target object to sign.
-// signURLConfig    the configuration for the signed URL
-//
-// string    returns the signed URL, when error is nil.
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (bucket Bucket) SignURL(objectKey string, method HTTPMethod, expiredInSec int64, options ...Option) (string, error) {
-	if expiredInSec < 0 {
-		return "", fmt.Errorf("invalid expires: %d, expires must bigger than 0", expiredInSec)
-	}
-	expiration := time.Now().Unix() + expiredInSec
-
-	params, err := getRawParams(options)
-	if err != nil {
-		return "", err
-	}
-
-	headers := make(map[string]string)
-	err = handleOptions(headers, options)
-	if err != nil {
-		return "", err
-	}
-
-	return bucket.Client.Conn.signURL(method, bucket.BucketName, objectKey, expiration, params, headers), nil
-}
-
-// PutObjectWithURL uploads an object with the URL. If the object exists, it will be overwritten.
-// PutObjectWithURL It will not generate minetype according to the key name.
-//
-// signedURL    signed URL.
-// reader    io.Reader the read instance for reading the data for the upload.
-// options    the options for uploading the data. The valid options are CacheControl, ContentDisposition, ContentEncoding,
-//            Expires, ServerSideEncryption, ObjectACL and custom metadata. Check out the following link for details:
-//            https://help.aliyun.com/document_detail/oss/api-reference/object/PutObject.html
-//
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (bucket Bucket) PutObjectWithURL(signedURL string, reader io.Reader, options ...Option) error {
-	resp, err := bucket.DoPutObjectWithURL(signedURL, reader, options)
-	if err != nil {
-		return err
-	}
-	defer resp.Body.Close()
-
-	return err
-}
-
-// PutObjectFromFileWithURL uploads an object from a local file with the signed URL.
-// PutObjectFromFileWithURL It does not generate mimetype according to object key's name or the local file name.
-//
-// signedURL    the signed URL.
-// filePath    local file path, such as dirfile.txt, for uploading.
-// options    options for uploading, same as the options in PutObject function.
-//
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (bucket Bucket) PutObjectFromFileWithURL(signedURL, filePath string, options ...Option) error {
-	fd, err := os.Open(filePath)
-	if err != nil {
-		return err
-	}
-	defer fd.Close()
-
-	resp, err := bucket.DoPutObjectWithURL(signedURL, fd, options)
-	if err != nil {
-		return err
-	}
-	defer resp.Body.Close()
-
-	return err
-}
-
-// DoPutObjectWithURL is the actual API that does the upload with URL work(internal for SDK)
-//
-// signedURL    the signed URL.
-// reader    io.Reader the read instance for getting the data to upload.
-// options    options for uploading.
-//
-// Response    the response object which contains the HTTP response.
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (bucket Bucket) DoPutObjectWithURL(signedURL string, reader io.Reader, options []Option) (*Response, error) {
-	listener := getProgressListener(options)
-
-	params := map[string]interface{}{}
-	resp, err := bucket.doURL("PUT", signedURL, params, options, reader, listener)
-	if err != nil {
-		return nil, err
-	}
-
-	if bucket.getConfig().IsEnableCRC {
-		err = checkCRC(resp, "DoPutObjectWithURL")
-		if err != nil {
-			return resp, err
-		}
-	}
-
-	err = checkRespCode(resp.StatusCode, []int{http.StatusOK})
-
-	return resp, err
-}
-
-// GetObjectWithURL downloads the object and returns the reader instance,  with the signed URL.
-//
-// signedURL    the signed URL.
-// options    options for downloading the object. Valid options are IfModifiedSince, IfUnmodifiedSince, IfMatch,
-//            IfNoneMatch, AcceptEncoding. For more information, check out the following link:
-//            https://help.aliyun.com/document_detail/oss/api-reference/object/GetObject.html
-//
-// io.ReadCloser    the reader object for getting the data from response. It needs be closed after the usage. It's only valid when error is nil.
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (bucket Bucket) GetObjectWithURL(signedURL string, options ...Option) (io.ReadCloser, error) {
-	result, err := bucket.DoGetObjectWithURL(signedURL, options)
-	if err != nil {
-		return nil, err
-	}
-	return result.Response, nil
-}
-
-// GetObjectToFileWithURL downloads the object into a local file with the signed URL.
-//
-// signedURL    the signed URL
-// filePath    the local file path to download to.
-// options    the options for downloading object. Check out the parameter options in function GetObject for the reference.
-//
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (bucket Bucket) GetObjectToFileWithURL(signedURL, filePath string, options ...Option) error {
-	tempFilePath := filePath + TempFileSuffix
-
-	// Get the object's content
-	result, err := bucket.DoGetObjectWithURL(signedURL, options)
-	if err != nil {
-		return err
-	}
-	defer result.Response.Close()
-
-	// If the file does not exist, create one. If exists, then overwrite it.
-	fd, err := os.OpenFile(tempFilePath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, FilePermMode)
-	if err != nil {
-		return err
-	}
-
-	// Save the data to the file.
-	_, err = io.Copy(fd, result.Response.Body)
-	fd.Close()
-	if err != nil {
-		return err
-	}
-
-	// Compare the CRC value. If CRC values do not match, return error.
-	hasRange, _, _ := isOptionSet(options, HTTPHeaderRange)
-	encodeOpt, _ := findOption(options, HTTPHeaderAcceptEncoding, nil)
-	acceptEncoding := ""
-	if encodeOpt != nil {
-		acceptEncoding = encodeOpt.(string)
-	}
-
-	if bucket.getConfig().IsEnableCRC && !hasRange && acceptEncoding != "gzip" {
-		result.Response.ClientCRC = result.ClientCRC.Sum64()
-		err = checkCRC(result.Response, "GetObjectToFileWithURL")
-		if err != nil {
-			os.Remove(tempFilePath)
-			return err
-		}
-	}
-
-	return os.Rename(tempFilePath, filePath)
-}
-
-// DoGetObjectWithURL is the actual API that downloads the file with the signed URL.
-//
-// signedURL    the signed URL.
-// options    the options for getting object. Check out parameter options in GetObject for the reference.
-//
-// GetObjectResult    the result object when the error is nil.
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (bucket Bucket) DoGetObjectWithURL(signedURL string, options []Option) (*GetObjectResult, error) {
-	params, _ := getRawParams(options)
-	resp, err := bucket.doURL("GET", signedURL, params, options, nil, nil)
-	if err != nil {
-		return nil, err
-	}
-
-	result := &GetObjectResult{
-		Response: resp,
-	}
-
-	// CRC
-	var crcCalc hash.Hash64
-	hasRange, _, _ := isOptionSet(options, HTTPHeaderRange)
-	if bucket.getConfig().IsEnableCRC && !hasRange {
-		crcCalc = crc64.New(crcTable())
-		result.ServerCRC = resp.ServerCRC
-		result.ClientCRC = crcCalc
-	}
-
-	// Progress
-	listener := getProgressListener(options)
-
-	contentLen, _ := strconv.ParseInt(resp.Headers.Get(HTTPHeaderContentLength), 10, 64)
-	resp.Body = TeeReader(resp.Body, crcCalc, contentLen, listener, nil)
-
-	return result, nil
-}
-
-//
-// ProcessObject apply process on the specified image file.
-//
-// The supported process includes resize, rotate, crop, watermark, format,
-// udf, customized style, etc.
-//
-//
-// objectKey	object key to process.
-// process	process string, such as "image/resize,w_100|sys/saveas,o_dGVzdC5qcGc,b_dGVzdA"
-//
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (bucket Bucket) ProcessObject(objectKey string, process string) (ProcessObjectResult, error) {
-	var out ProcessObjectResult
-	params := map[string]interface{}{}
-	params["x-oss-process"] = nil
-	processData := fmt.Sprintf("%v=%v", "x-oss-process", process)
-	data := strings.NewReader(processData)
-	resp, err := bucket.do("POST", objectKey, params, nil, data, nil)
-	if err != nil {
-		return out, err
-	}
-	defer resp.Body.Close()
-
-	err = jsonUnmarshal(resp.Body, &out)
-	return out, err
-}
-
-// Private
-func (bucket Bucket) do(method, objectName string, params map[string]interface{}, options []Option,
-	data io.Reader, listener ProgressListener) (*Response, error) {
-	headers := make(map[string]string)
-	err := handleOptions(headers, options)
-	if err != nil {
-		return nil, err
-	}
-	return bucket.Client.Conn.Do(method, bucket.BucketName, objectName,
-		params, headers, data, 0, listener)
-}
-
-func (bucket Bucket) doURL(method HTTPMethod, signedURL string, params map[string]interface{}, options []Option,
-	data io.Reader, listener ProgressListener) (*Response, error) {
-	headers := make(map[string]string)
-	err := handleOptions(headers, options)
-	if err != nil {
-		return nil, err
-	}
-	return bucket.Client.Conn.DoURL(method, signedURL, headers, data, 0, listener)
-}
-
-func (bucket Bucket) getConfig() *Config {
-	return bucket.Client.Config
-}
-
-func addContentType(options []Option, keys ...string) []Option {
-	typ := TypeByExtension("")
-	for _, key := range keys {
-		typ = TypeByExtension(key)
-		if typ != "" {
-			break
-		}
-	}
-
-	if typ == "" {
-		typ = "application/octet-stream"
-	}
-
-	opts := []Option{ContentType(typ)}
-	opts = append(opts, options...)
-
-	return opts
-}

+ 0 - 805
vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/client.go

@@ -1,805 +0,0 @@
-// Package oss implements functions for access oss service.
-// It has two main struct Client and Bucket.
-package oss
-
-import (
-	"bytes"
-	"encoding/xml"
-	"fmt"
-	"io"
-	"log"
-	"net/http"
-	"strings"
-	"time"
-)
-
-// Client SDK's entry point. It's for bucket related options such as create/delete/set bucket (such as set/get ACL/lifecycle/referer/logging/website).
-// Object related operations are done by Bucket class.
-// Users use oss.New to create Client instance.
-//
-type (
-	// Client OSS client
-	Client struct {
-		Config     *Config      // OSS client configuration
-		Conn       *Conn        // Send HTTP request
-		HTTPClient *http.Client //http.Client to use - if nil will make its own
-	}
-
-	// ClientOption client option such as UseCname, Timeout, SecurityToken.
-	ClientOption func(*Client)
-)
-
-// New creates a new client.
-//
-// endpoint    the OSS datacenter endpoint such as http://oss-cn-hangzhou.aliyuncs.com .
-// accessKeyId    access key Id.
-// accessKeySecret    access key secret.
-//
-// Client    creates the new client instance, the returned value is valid when error is nil.
-// error    it's nil if no error, otherwise it's an error object.
-//
-func New(endpoint, accessKeyID, accessKeySecret string, options ...ClientOption) (*Client, error) {
-	// Configuration
-	config := getDefaultOssConfig()
-	config.Endpoint = endpoint
-	config.AccessKeyID = accessKeyID
-	config.AccessKeySecret = accessKeySecret
-
-	// URL parse
-	url := &urlMaker{}
-	url.Init(config.Endpoint, config.IsCname, config.IsUseProxy)
-
-	// HTTP connect
-	conn := &Conn{config: config, url: url}
-
-	// OSS client
-	client := &Client{
-		Config: config,
-		Conn:   conn,
-	}
-
-	// Client options parse
-	for _, option := range options {
-		option(client)
-	}
-
-	// Create HTTP connection
-	err := conn.init(config, url, client.HTTPClient)
-
-	return client, err
-}
-
-// Bucket gets the bucket instance.
-//
-// bucketName    the bucket name.
-// Bucket    the bucket object, when error is nil.
-//
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (client Client) Bucket(bucketName string) (*Bucket, error) {
-	return &Bucket{
-		client,
-		bucketName,
-	}, nil
-}
-
-// CreateBucket creates a bucket.
-//
-// bucketName    the bucket name, it's globably unique and immutable. The bucket name can only consist of lowercase letters, numbers and dash ('-').
-//               It must start with lowercase letter or number and the length can only be between 3 and 255.
-// options    options for creating the bucket, with optional ACL. The ACL could be ACLPrivate, ACLPublicRead, and ACLPublicReadWrite. By default it's ACLPrivate.
-//            It could also be specified with StorageClass option, which supports StorageStandard, StorageIA(infrequent access), StorageArchive.
-//
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (client Client) CreateBucket(bucketName string, options ...Option) error {
-	headers := make(map[string]string)
-	handleOptions(headers, options)
-
-	buffer := new(bytes.Buffer)
-
-	isOptSet, val, _ := isOptionSet(options, storageClass)
-	if isOptSet {
-		cbConfig := createBucketConfiguration{StorageClass: val.(StorageClassType)}
-		bs, err := xml.Marshal(cbConfig)
-		if err != nil {
-			return err
-		}
-		buffer.Write(bs)
-
-		contentType := http.DetectContentType(buffer.Bytes())
-		headers[HTTPHeaderContentType] = contentType
-	}
-
-	params := map[string]interface{}{}
-	resp, err := client.do("PUT", bucketName, params, headers, buffer)
-	if err != nil {
-		return err
-	}
-
-	defer resp.Body.Close()
-	return checkRespCode(resp.StatusCode, []int{http.StatusOK})
-}
-
-// ListBuckets lists buckets of the current account under the given endpoint, with optional filters.
-//
-// options    specifies the filters such as Prefix, Marker and MaxKeys. Prefix is the bucket name's prefix filter.
-//            And marker makes sure the returned buckets' name are greater than it in lexicographic order.
-//            Maxkeys limits the max keys to return, and by default it's 100 and up to 1000.
-//            For the common usage scenario, please check out list_bucket.go in the sample.
-// ListBucketsResponse    the response object if error is nil.
-//
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (client Client) ListBuckets(options ...Option) (ListBucketsResult, error) {
-	var out ListBucketsResult
-
-	params, err := getRawParams(options)
-	if err != nil {
-		return out, err
-	}
-
-	resp, err := client.do("GET", "", params, nil, nil)
-	if err != nil {
-		return out, err
-	}
-	defer resp.Body.Close()
-
-	err = xmlUnmarshal(resp.Body, &out)
-	return out, err
-}
-
-// IsBucketExist checks if the bucket exists
-//
-// bucketName    the bucket name.
-//
-// bool    true if it exists, and it's only valid when error is nil.
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (client Client) IsBucketExist(bucketName string) (bool, error) {
-	listRes, err := client.ListBuckets(Prefix(bucketName), MaxKeys(1))
-	if err != nil {
-		return false, err
-	}
-
-	if len(listRes.Buckets) == 1 && listRes.Buckets[0].Name == bucketName {
-		return true, nil
-	}
-	return false, nil
-}
-
-// DeleteBucket deletes the bucket. Only empty bucket can be deleted (no object and parts).
-//
-// bucketName    the bucket name.
-//
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (client Client) DeleteBucket(bucketName string) error {
-	params := map[string]interface{}{}
-	resp, err := client.do("DELETE", bucketName, params, nil, nil)
-	if err != nil {
-		return err
-	}
-
-	defer resp.Body.Close()
-	return checkRespCode(resp.StatusCode, []int{http.StatusNoContent})
-}
-
-// GetBucketLocation gets the bucket location.
-//
-// Checks out the following link for more information :
-// https://help.aliyun.com/document_detail/oss/user_guide/oss_concept/endpoint.html
-//
-// bucketName    the bucket name
-//
-// string    bucket's datacenter location
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (client Client) GetBucketLocation(bucketName string) (string, error) {
-	params := map[string]interface{}{}
-	params["location"] = nil
-	resp, err := client.do("GET", bucketName, params, nil, nil)
-	if err != nil {
-		return "", err
-	}
-	defer resp.Body.Close()
-
-	var LocationConstraint string
-	err = xmlUnmarshal(resp.Body, &LocationConstraint)
-	return LocationConstraint, err
-}
-
-// SetBucketACL sets bucket's ACL.
-//
-// bucketName    the bucket name
-// bucketAcl    the bucket ACL: ACLPrivate, ACLPublicRead and ACLPublicReadWrite.
-//
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (client Client) SetBucketACL(bucketName string, bucketACL ACLType) error {
-	headers := map[string]string{HTTPHeaderOssACL: string(bucketACL)}
-	params := map[string]interface{}{}
-	resp, err := client.do("PUT", bucketName, params, headers, nil)
-	if err != nil {
-		return err
-	}
-	defer resp.Body.Close()
-	return checkRespCode(resp.StatusCode, []int{http.StatusOK})
-}
-
-// GetBucketACL gets the bucket ACL.
-//
-// bucketName    the bucket name.
-//
-// GetBucketAclResponse    the result object, and it's only valid when error is nil.
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (client Client) GetBucketACL(bucketName string) (GetBucketACLResult, error) {
-	var out GetBucketACLResult
-	params := map[string]interface{}{}
-	params["acl"] = nil
-	resp, err := client.do("GET", bucketName, params, nil, nil)
-	if err != nil {
-		return out, err
-	}
-	defer resp.Body.Close()
-
-	err = xmlUnmarshal(resp.Body, &out)
-	return out, err
-}
-
-// SetBucketLifecycle sets the bucket's lifecycle.
-//
-// For more information, checks out following link:
-// https://help.aliyun.com/document_detail/oss/user_guide/manage_object/object_lifecycle.html
-//
-// bucketName    the bucket name.
-// rules    the lifecycle rules. There're two kind of rules: absolute time expiration and relative time expiration in days and day/month/year respectively.
-//          Check out sample/bucket_lifecycle.go for more details.
-//
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (client Client) SetBucketLifecycle(bucketName string, rules []LifecycleRule) error {
-	lxml := lifecycleXML{Rules: convLifecycleRule(rules)}
-	bs, err := xml.Marshal(lxml)
-	if err != nil {
-		return err
-	}
-	buffer := new(bytes.Buffer)
-	buffer.Write(bs)
-
-	contentType := http.DetectContentType(buffer.Bytes())
-	headers := map[string]string{}
-	headers[HTTPHeaderContentType] = contentType
-
-	params := map[string]interface{}{}
-	params["lifecycle"] = nil
-	resp, err := client.do("PUT", bucketName, params, headers, buffer)
-	if err != nil {
-		return err
-	}
-	defer resp.Body.Close()
-	return checkRespCode(resp.StatusCode, []int{http.StatusOK})
-}
-
-// DeleteBucketLifecycle deletes the bucket's lifecycle.
-//
-//
-// bucketName    the bucket name.
-//
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (client Client) DeleteBucketLifecycle(bucketName string) error {
-	params := map[string]interface{}{}
-	params["lifecycle"] = nil
-	resp, err := client.do("DELETE", bucketName, params, nil, nil)
-	if err != nil {
-		return err
-	}
-	defer resp.Body.Close()
-	return checkRespCode(resp.StatusCode, []int{http.StatusNoContent})
-}
-
-// GetBucketLifecycle gets the bucket's lifecycle settings.
-//
-// bucketName    the bucket name.
-//
-// GetBucketLifecycleResponse    the result object upon successful request. It's only valid when error is nil.
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (client Client) GetBucketLifecycle(bucketName string) (GetBucketLifecycleResult, error) {
-	var out GetBucketLifecycleResult
-	params := map[string]interface{}{}
-	params["lifecycle"] = nil
-	resp, err := client.do("GET", bucketName, params, nil, nil)
-	if err != nil {
-		return out, err
-	}
-	defer resp.Body.Close()
-
-	err = xmlUnmarshal(resp.Body, &out)
-	return out, err
-}
-
-// SetBucketReferer sets the bucket's referer whitelist and the flag if allowing empty referrer.
-//
-// To avoid stealing link on OSS data, OSS supports the HTTP referrer header. A whitelist referrer could be set either by API or web console, as well as
-// the allowing empty referrer flag. Note that this applies to requests from webbrowser only.
-// For example, for a bucket os-example and its referrer http://www.aliyun.com, all requests from this URL could access the bucket.
-// For more information, please check out this link :
-// https://help.aliyun.com/document_detail/oss/user_guide/security_management/referer.html
-//
-// bucketName    the bucket name.
-// referers    the referrer white list. A bucket could have a referrer list and each referrer supports one '*' and multiple '?' as wildcards.
-//             The sample could be found in sample/bucket_referer.go
-// allowEmptyReferer    the flag of allowing empty referrer. By default it's true.
-//
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (client Client) SetBucketReferer(bucketName string, referers []string, allowEmptyReferer bool) error {
-	rxml := RefererXML{}
-	rxml.AllowEmptyReferer = allowEmptyReferer
-	if referers == nil {
-		rxml.RefererList = append(rxml.RefererList, "")
-	} else {
-		for _, referer := range referers {
-			rxml.RefererList = append(rxml.RefererList, referer)
-		}
-	}
-
-	bs, err := xml.Marshal(rxml)
-	if err != nil {
-		return err
-	}
-	buffer := new(bytes.Buffer)
-	buffer.Write(bs)
-
-	contentType := http.DetectContentType(buffer.Bytes())
-	headers := map[string]string{}
-	headers[HTTPHeaderContentType] = contentType
-
-	params := map[string]interface{}{}
-	params["referer"] = nil
-	resp, err := client.do("PUT", bucketName, params, headers, buffer)
-	if err != nil {
-		return err
-	}
-	defer resp.Body.Close()
-	return checkRespCode(resp.StatusCode, []int{http.StatusOK})
-}
-
-// GetBucketReferer gets the bucket's referrer white list.
-//
-// bucketName    the bucket name.
-//
-// GetBucketRefererResponse    the result object upon successful request. It's only valid when error is nil.
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (client Client) GetBucketReferer(bucketName string) (GetBucketRefererResult, error) {
-	var out GetBucketRefererResult
-	params := map[string]interface{}{}
-	params["referer"] = nil
-	resp, err := client.do("GET", bucketName, params, nil, nil)
-	if err != nil {
-		return out, err
-	}
-	defer resp.Body.Close()
-
-	err = xmlUnmarshal(resp.Body, &out)
-	return out, err
-}
-
-// SetBucketLogging sets the bucket logging settings.
-//
-// OSS could automatically store the access log. Only the bucket owner could enable the logging.
-// Once enabled, OSS would save all the access log into hourly log files in a specified bucket.
-// For more information, please check out https://help.aliyun.com/document_detail/oss/user_guide/security_management/logging.html
-//
-// bucketName    bucket name to enable the log.
-// targetBucket    the target bucket name to store the log files.
-// targetPrefix    the log files' prefix.
-//
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (client Client) SetBucketLogging(bucketName, targetBucket, targetPrefix string,
-	isEnable bool) error {
-	var err error
-	var bs []byte
-	if isEnable {
-		lxml := LoggingXML{}
-		lxml.LoggingEnabled.TargetBucket = targetBucket
-		lxml.LoggingEnabled.TargetPrefix = targetPrefix
-		bs, err = xml.Marshal(lxml)
-	} else {
-		lxml := loggingXMLEmpty{}
-		bs, err = xml.Marshal(lxml)
-	}
-
-	if err != nil {
-		return err
-	}
-
-	buffer := new(bytes.Buffer)
-	buffer.Write(bs)
-
-	contentType := http.DetectContentType(buffer.Bytes())
-	headers := map[string]string{}
-	headers[HTTPHeaderContentType] = contentType
-
-	params := map[string]interface{}{}
-	params["logging"] = nil
-	resp, err := client.do("PUT", bucketName, params, headers, buffer)
-	if err != nil {
-		return err
-	}
-	defer resp.Body.Close()
-	return checkRespCode(resp.StatusCode, []int{http.StatusOK})
-}
-
-// DeleteBucketLogging deletes the logging configuration to disable the logging on the bucket.
-//
-// bucketName    the bucket name to disable the logging.
-//
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (client Client) DeleteBucketLogging(bucketName string) error {
-	params := map[string]interface{}{}
-	params["logging"] = nil
-	resp, err := client.do("DELETE", bucketName, params, nil, nil)
-	if err != nil {
-		return err
-	}
-	defer resp.Body.Close()
-	return checkRespCode(resp.StatusCode, []int{http.StatusNoContent})
-}
-
-// GetBucketLogging gets the bucket's logging settings
-//
-// bucketName    the bucket name
-// GetBucketLoggingResponse    the result object upon successful request. It's only valid when error is nil.
-//
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (client Client) GetBucketLogging(bucketName string) (GetBucketLoggingResult, error) {
-	var out GetBucketLoggingResult
-	params := map[string]interface{}{}
-	params["logging"] = nil
-	resp, err := client.do("GET", bucketName, params, nil, nil)
-	if err != nil {
-		return out, err
-	}
-	defer resp.Body.Close()
-
-	err = xmlUnmarshal(resp.Body, &out)
-	return out, err
-}
-
-// SetBucketWebsite sets the bucket's static website's index and error page.
-//
-// OSS supports static web site hosting for the bucket data. When the bucket is enabled with that, you can access the file in the bucket like the way to access a static website.
-// For more information, please check out: https://help.aliyun.com/document_detail/oss/user_guide/static_host_website.html
-//
-// bucketName    the bucket name to enable static web site.
-// indexDocument    index page.
-// errorDocument    error page.
-//
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (client Client) SetBucketWebsite(bucketName, indexDocument, errorDocument string) error {
-	wxml := WebsiteXML{}
-	wxml.IndexDocument.Suffix = indexDocument
-	wxml.ErrorDocument.Key = errorDocument
-
-	bs, err := xml.Marshal(wxml)
-	if err != nil {
-		return err
-	}
-	buffer := new(bytes.Buffer)
-	buffer.Write(bs)
-
-	contentType := http.DetectContentType(buffer.Bytes())
-	headers := make(map[string]string)
-	headers[HTTPHeaderContentType] = contentType
-
-	params := map[string]interface{}{}
-	params["website"] = nil
-	resp, err := client.do("PUT", bucketName, params, headers, buffer)
-	if err != nil {
-		return err
-	}
-	defer resp.Body.Close()
-	return checkRespCode(resp.StatusCode, []int{http.StatusOK})
-}
-
-// DeleteBucketWebsite deletes the bucket's static web site settings.
-//
-// bucketName    the bucket name.
-//
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (client Client) DeleteBucketWebsite(bucketName string) error {
-	params := map[string]interface{}{}
-	params["website"] = nil
-	resp, err := client.do("DELETE", bucketName, params, nil, nil)
-	if err != nil {
-		return err
-	}
-	defer resp.Body.Close()
-	return checkRespCode(resp.StatusCode, []int{http.StatusNoContent})
-}
-
-// GetBucketWebsite gets the bucket's default page (index page) and the error page.
-//
-// bucketName    the bucket name
-//
-// GetBucketWebsiteResponse    the result object upon successful request. It's only valid when error is nil.
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (client Client) GetBucketWebsite(bucketName string) (GetBucketWebsiteResult, error) {
-	var out GetBucketWebsiteResult
-	params := map[string]interface{}{}
-	params["website"] = nil
-	resp, err := client.do("GET", bucketName, params, nil, nil)
-	if err != nil {
-		return out, err
-	}
-	defer resp.Body.Close()
-
-	err = xmlUnmarshal(resp.Body, &out)
-	return out, err
-}
-
-// SetBucketCORS sets the bucket's CORS rules
-//
-// For more information, please check out https://help.aliyun.com/document_detail/oss/user_guide/security_management/cors.html
-//
-// bucketName    the bucket name
-// corsRules    the CORS rules to set. The related sample code is in sample/bucket_cors.go.
-//
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (client Client) SetBucketCORS(bucketName string, corsRules []CORSRule) error {
-	corsxml := CORSXML{}
-	for _, v := range corsRules {
-		cr := CORSRule{}
-		cr.AllowedMethod = v.AllowedMethod
-		cr.AllowedOrigin = v.AllowedOrigin
-		cr.AllowedHeader = v.AllowedHeader
-		cr.ExposeHeader = v.ExposeHeader
-		cr.MaxAgeSeconds = v.MaxAgeSeconds
-		corsxml.CORSRules = append(corsxml.CORSRules, cr)
-	}
-
-	bs, err := xml.Marshal(corsxml)
-	if err != nil {
-		return err
-	}
-	buffer := new(bytes.Buffer)
-	buffer.Write(bs)
-
-	contentType := http.DetectContentType(buffer.Bytes())
-	headers := map[string]string{}
-	headers[HTTPHeaderContentType] = contentType
-
-	params := map[string]interface{}{}
-	params["cors"] = nil
-	resp, err := client.do("PUT", bucketName, params, headers, buffer)
-	if err != nil {
-		return err
-	}
-	defer resp.Body.Close()
-	return checkRespCode(resp.StatusCode, []int{http.StatusOK})
-}
-
-// DeleteBucketCORS deletes the bucket's static website settings.
-//
-// bucketName    the bucket name.
-//
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (client Client) DeleteBucketCORS(bucketName string) error {
-	params := map[string]interface{}{}
-	params["cors"] = nil
-	resp, err := client.do("DELETE", bucketName, params, nil, nil)
-	if err != nil {
-		return err
-	}
-	defer resp.Body.Close()
-	return checkRespCode(resp.StatusCode, []int{http.StatusNoContent})
-}
-
-// GetBucketCORS gets the bucket's CORS settings.
-//
-// bucketName    the bucket name.
-// GetBucketCORSResult    the result object upon successful request. It's only valid when error is nil.
-//
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (client Client) GetBucketCORS(bucketName string) (GetBucketCORSResult, error) {
-	var out GetBucketCORSResult
-	params := map[string]interface{}{}
-	params["cors"] = nil
-	resp, err := client.do("GET", bucketName, params, nil, nil)
-	if err != nil {
-		return out, err
-	}
-	defer resp.Body.Close()
-
-	err = xmlUnmarshal(resp.Body, &out)
-	return out, err
-}
-
-// GetBucketInfo gets the bucket information.
-//
-// bucketName    the bucket name.
-// GetBucketInfoResult    the result object upon successful request. It's only valid when error is nil.
-//
-// error    it's nil if no error, otherwise it's an error object.
-//
-func (client Client) GetBucketInfo(bucketName string) (GetBucketInfoResult, error) {
-	var out GetBucketInfoResult
-	params := map[string]interface{}{}
-	params["bucketInfo"] = nil
-	resp, err := client.do("GET", bucketName, params, nil, nil)
-	if err != nil {
-		return out, err
-	}
-	defer resp.Body.Close()
-
-	err = xmlUnmarshal(resp.Body, &out)
-	return out, err
-}
-
-// LimitUploadSpeed: set upload bandwidth limit speed,default is 0,unlimited
-// upSpeed: KB/s, 0 is unlimited,default is 0
-// error:it's nil if success, otherwise failure
-func (client Client) LimitUploadSpeed(upSpeed int) error {
-	if client.Config == nil {
-		return fmt.Errorf("client config is nil")
-	}
-	return client.Config.LimitUploadSpeed(upSpeed)
-}
-
-// UseCname sets the flag of using CName. By default it's false.
-//
-// isUseCname    true: the endpoint has the CName, false: the endpoint does not have cname. Default is false.
-//
-func UseCname(isUseCname bool) ClientOption {
-	return func(client *Client) {
-		client.Config.IsCname = isUseCname
-		client.Conn.url.Init(client.Config.Endpoint, client.Config.IsCname, client.Config.IsUseProxy)
-	}
-}
-
-// Timeout sets the HTTP timeout in seconds.
-//
-// connectTimeoutSec    HTTP timeout in seconds. Default is 10 seconds. 0 means infinite (not recommended)
-// readWriteTimeout    HTTP read or write's timeout in seconds. Default is 20 seconds. 0 means infinite.
-//
-func Timeout(connectTimeoutSec, readWriteTimeout int64) ClientOption {
-	return func(client *Client) {
-		client.Config.HTTPTimeout.ConnectTimeout =
-			time.Second * time.Duration(connectTimeoutSec)
-		client.Config.HTTPTimeout.ReadWriteTimeout =
-			time.Second * time.Duration(readWriteTimeout)
-		client.Config.HTTPTimeout.HeaderTimeout =
-			time.Second * time.Duration(readWriteTimeout)
-		client.Config.HTTPTimeout.IdleConnTimeout =
-			time.Second * time.Duration(readWriteTimeout)
-		client.Config.HTTPTimeout.LongTimeout =
-			time.Second * time.Duration(readWriteTimeout*10)
-	}
-}
-
-// SecurityToken sets the temporary user's SecurityToken.
-//
-// token    STS token
-//
-func SecurityToken(token string) ClientOption {
-	return func(client *Client) {
-		client.Config.SecurityToken = strings.TrimSpace(token)
-	}
-}
-
-// EnableMD5 enables MD5 validation.
-//
-// isEnableMD5    true: enable MD5 validation; false: disable MD5 validation.
-//
-func EnableMD5(isEnableMD5 bool) ClientOption {
-	return func(client *Client) {
-		client.Config.IsEnableMD5 = isEnableMD5
-	}
-}
-
-// MD5ThresholdCalcInMemory sets the memory usage threshold for computing the MD5, default is 16MB.
-//
-// threshold    the memory threshold in bytes. When the uploaded content is more than 16MB, the temp file is used for computing the MD5.
-//
-func MD5ThresholdCalcInMemory(threshold int64) ClientOption {
-	return func(client *Client) {
-		client.Config.MD5Threshold = threshold
-	}
-}
-
-// EnableCRC enables the CRC checksum. Default is true.
-//
-// isEnableCRC    true: enable CRC checksum; false: disable the CRC checksum.
-//
-func EnableCRC(isEnableCRC bool) ClientOption {
-	return func(client *Client) {
-		client.Config.IsEnableCRC = isEnableCRC
-	}
-}
-
-// UserAgent specifies UserAgent. The default is aliyun-sdk-go/1.2.0 (windows/-/amd64;go1.5.2).
-//
-// userAgent    the user agent string.
-//
-func UserAgent(userAgent string) ClientOption {
-	return func(client *Client) {
-		client.Config.UserAgent = userAgent
-	}
-}
-
-// Proxy sets the proxy (optional). The default is not using proxy.
-//
-// proxyHost    the proxy host in the format "host:port". For example, proxy.com:80 .
-//
-func Proxy(proxyHost string) ClientOption {
-	return func(client *Client) {
-		client.Config.IsUseProxy = true
-		client.Config.ProxyHost = proxyHost
-		client.Conn.url.Init(client.Config.Endpoint, client.Config.IsCname, client.Config.IsUseProxy)
-	}
-}
-
-// AuthProxy sets the proxy information with user name and password.
-//
-// proxyHost    the proxy host in the format "host:port". For example, proxy.com:80 .
-// proxyUser    the proxy user name.
-// proxyPassword    the proxy password.
-//
-func AuthProxy(proxyHost, proxyUser, proxyPassword string) ClientOption {
-	return func(client *Client) {
-		client.Config.IsUseProxy = true
-		client.Config.ProxyHost = proxyHost
-		client.Config.IsAuthProxy = true
-		client.Config.ProxyUser = proxyUser
-		client.Config.ProxyPassword = proxyPassword
-		client.Conn.url.Init(client.Config.Endpoint, client.Config.IsCname, client.Config.IsUseProxy)
-	}
-}
-
-//
-// HTTPClient sets the http.Client in use to the one passed in
-//
-func HTTPClient(HTTPClient *http.Client) ClientOption {
-	return func(client *Client) {
-		client.HTTPClient = HTTPClient
-	}
-}
-
-//
-// SetLogLevel sets the oss sdk log level
-//
-func SetLogLevel(LogLevel int) ClientOption {
-	return func(client *Client) {
-		client.Config.LogLevel = LogLevel
-	}
-}
-
-//
-// SetLogLevel sets the oss sdk log level
-//
-func SetLogger(Logger *log.Logger) ClientOption {
-	return func(client *Client) {
-		client.Config.Logger = Logger
-	}
-}
-
-// Private
-func (client Client) do(method, bucketName string, params map[string]interface{},
-	headers map[string]string, data io.Reader) (*Response, error) {
-	return client.Conn.Do(method, bucketName, "", params,
-		headers, data, 0, nil)
-}

+ 0 - 128
vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/conf.go

@@ -1,128 +0,0 @@
-package oss
-
-import (
-	"bytes"
-	"fmt"
-	"log"
-	"os"
-	"time"
-)
-
-const (
-	LogOff = iota
-	Error
-	Warn
-	Info
-	Debug
-)
-
-var LogTag = []string{"[error]", "[warn]", "[info]", "[debug]"}
-
-// HTTPTimeout defines HTTP timeout.
-type HTTPTimeout struct {
-	ConnectTimeout   time.Duration
-	ReadWriteTimeout time.Duration
-	HeaderTimeout    time.Duration
-	LongTimeout      time.Duration
-	IdleConnTimeout  time.Duration
-}
-
-type HTTPMaxConns struct {
-	MaxIdleConns        int
-	MaxIdleConnsPerHost int
-}
-
-// Config defines oss configuration
-type Config struct {
-	Endpoint         string       // OSS endpoint
-	AccessKeyID      string       // AccessId
-	AccessKeySecret  string       // AccessKey
-	RetryTimes       uint         // Retry count by default it's 5.
-	UserAgent        string       // SDK name/version/system information
-	IsDebug          bool         // Enable debug mode. Default is false.
-	Timeout          uint         // Timeout in seconds. By default it's 60.
-	SecurityToken    string       // STS Token
-	IsCname          bool         // If cname is in the endpoint.
-	HTTPTimeout      HTTPTimeout  // HTTP timeout
-	HTTPMaxConns     HTTPMaxConns // Http max connections
-	IsUseProxy       bool         // Flag of using proxy.
-	ProxyHost        string       // Flag of using proxy host.
-	IsAuthProxy      bool         // Flag of needing authentication.
-	ProxyUser        string       // Proxy user
-	ProxyPassword    string       // Proxy password
-	IsEnableMD5      bool         // Flag of enabling MD5 for upload.
-	MD5Threshold     int64        // Memory footprint threshold for each MD5 computation (16MB is the default), in byte. When the data is more than that, temp file is used.
-	IsEnableCRC      bool         // Flag of enabling CRC for upload.
-	LogLevel         int          // Log level
-	Logger           *log.Logger  // For write log
-	UploadLimitSpeed int          // Upload limit speed:KB/s, 0 is unlimited
-	UploadLimiter    *OssLimiter  // Bandwidth limit reader for upload
-}
-
-// LimitUploadSpeed, uploadSpeed:KB/s, 0 is unlimited,default is 0
-func (config *Config) LimitUploadSpeed(uploadSpeed int) error {
-	if uploadSpeed < 0 {
-		return fmt.Errorf("erro,speed is less than 0")
-	} else if uploadSpeed == 0 {
-		config.UploadLimitSpeed = 0
-		config.UploadLimiter = nil
-		return nil
-	}
-
-	var err error
-	config.UploadLimiter, err = GetOssLimiter(uploadSpeed)
-	if err == nil {
-		config.UploadLimitSpeed = uploadSpeed
-	}
-	return err
-}
-
-// WriteLog
-func (config *Config) WriteLog(LogLevel int, format string, a ...interface{}) {
-	if config.LogLevel < LogLevel || config.Logger == nil {
-		return
-	}
-
-	var logBuffer bytes.Buffer
-	logBuffer.WriteString(LogTag[LogLevel-1])
-	logBuffer.WriteString(fmt.Sprintf(format, a...))
-	config.Logger.Printf("%s", logBuffer.String())
-}
-
-// getDefaultOssConfig gets the default configuration.
-func getDefaultOssConfig() *Config {
-	config := Config{}
-
-	config.Endpoint = ""
-	config.AccessKeyID = ""
-	config.AccessKeySecret = ""
-	config.RetryTimes = 5
-	config.IsDebug = false
-	config.UserAgent = userAgent()
-	config.Timeout = 60 // Seconds
-	config.SecurityToken = ""
-	config.IsCname = false
-
-	config.HTTPTimeout.ConnectTimeout = time.Second * 30   // 30s
-	config.HTTPTimeout.ReadWriteTimeout = time.Second * 60 // 60s
-	config.HTTPTimeout.HeaderTimeout = time.Second * 60    // 60s
-	config.HTTPTimeout.LongTimeout = time.Second * 300     // 300s
-	config.HTTPTimeout.IdleConnTimeout = time.Second * 50  // 50s
-	config.HTTPMaxConns.MaxIdleConns = 100
-	config.HTTPMaxConns.MaxIdleConnsPerHost = 100
-
-	config.IsUseProxy = false
-	config.ProxyHost = ""
-	config.IsAuthProxy = false
-	config.ProxyUser = ""
-	config.ProxyPassword = ""
-
-	config.MD5Threshold = 16 * 1024 * 1024 // 16MB
-	config.IsEnableMD5 = false
-	config.IsEnableCRC = true
-
-	config.LogLevel = LogOff
-	config.Logger = log.New(os.Stdout, "", log.LstdFlags)
-
-	return &config
-}

+ 0 - 730
vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/conn.go

@@ -1,730 +0,0 @@
-package oss
-
-import (
-	"bytes"
-	"crypto/md5"
-	"encoding/base64"
-	"encoding/json"
-	"encoding/xml"
-	"fmt"
-	"hash"
-	"io"
-	"io/ioutil"
-	"net"
-	"net/http"
-	"net/url"
-	"os"
-	"sort"
-	"strconv"
-	"strings"
-	"time"
-)
-
-// Conn defines OSS Conn
-type Conn struct {
-	config *Config
-	url    *urlMaker
-	client *http.Client
-}
-
-var signKeyList = []string{"acl", "uploads", "location", "cors", "logging", "website", "referer", "lifecycle", "delete", "append", "tagging", "objectMeta", "uploadId", "partNumber", "security-token", "position", "img", "style", "styleName", "replication", "replicationProgress", "replicationLocation", "cname", "bucketInfo", "comp", "qos", "live", "status", "vod", "startTime", "endTime", "symlink", "x-oss-process", "response-content-type", "response-content-language", "response-expires", "response-cache-control", "response-content-disposition", "response-content-encoding", "udf", "udfName", "udfImage", "udfId", "udfImageDesc", "udfApplication", "comp", "udfApplicationLog", "restore", "callback", "callback-var"}
-
-// init initializes Conn
-func (conn *Conn) init(config *Config, urlMaker *urlMaker, client *http.Client) error {
-	if client == nil {
-		// New transport
-		transport := newTransport(conn, config)
-
-		// Proxy
-		if conn.config.IsUseProxy {
-			proxyURL, err := url.Parse(config.ProxyHost)
-			if err != nil {
-				return err
-			}
-			transport.Proxy = http.ProxyURL(proxyURL)
-		}
-		client = &http.Client{Transport: transport}
-	}
-
-	conn.config = config
-	conn.url = urlMaker
-	conn.client = client
-
-	return nil
-}
-
-// Do sends request and returns the response
-func (conn Conn) Do(method, bucketName, objectName string, params map[string]interface{}, headers map[string]string,
-	data io.Reader, initCRC uint64, listener ProgressListener) (*Response, error) {
-	urlParams := conn.getURLParams(params)
-	subResource := conn.getSubResource(params)
-	uri := conn.url.getURL(bucketName, objectName, urlParams)
-	resource := conn.url.getResource(bucketName, objectName, subResource)
-	return conn.doRequest(method, uri, resource, headers, data, initCRC, listener)
-}
-
-// DoURL sends the request with signed URL and returns the response result.
-func (conn Conn) DoURL(method HTTPMethod, signedURL string, headers map[string]string,
-	data io.Reader, initCRC uint64, listener ProgressListener) (*Response, error) {
-	// Get URI from signedURL
-	uri, err := url.ParseRequestURI(signedURL)
-	if err != nil {
-		return nil, err
-	}
-
-	m := strings.ToUpper(string(method))
-	req := &http.Request{
-		Method:     m,
-		URL:        uri,
-		Proto:      "HTTP/1.1",
-		ProtoMajor: 1,
-		ProtoMinor: 1,
-		Header:     make(http.Header),
-		Host:       uri.Host,
-	}
-
-	tracker := &readerTracker{completedBytes: 0}
-	fd, crc := conn.handleBody(req, data, initCRC, listener, tracker)
-	if fd != nil {
-		defer func() {
-			fd.Close()
-			os.Remove(fd.Name())
-		}()
-	}
-
-	if conn.config.IsAuthProxy {
-		auth := conn.config.ProxyUser + ":" + conn.config.ProxyPassword
-		basic := "Basic " + base64.StdEncoding.EncodeToString([]byte(auth))
-		req.Header.Set("Proxy-Authorization", basic)
-	}
-
-	req.Header.Set(HTTPHeaderHost, conn.config.Endpoint)
-	req.Header.Set(HTTPHeaderUserAgent, conn.config.UserAgent)
-
-	if headers != nil {
-		for k, v := range headers {
-			req.Header.Set(k, v)
-		}
-	}
-
-	// Transfer started
-	event := newProgressEvent(TransferStartedEvent, 0, req.ContentLength)
-	publishProgress(listener, event)
-
-	if conn.config.LogLevel >= Debug {
-		conn.LoggerHttpReq(req)
-	}
-
-	resp, err := conn.client.Do(req)
-	if err != nil {
-		// Transfer failed
-		event = newProgressEvent(TransferFailedEvent, tracker.completedBytes, req.ContentLength)
-		publishProgress(listener, event)
-		return nil, err
-	}
-
-	if conn.config.LogLevel >= Debug {
-		//print out http resp
-		conn.LoggerHttpResp(req, resp)
-	}
-
-	// Transfer completed
-	event = newProgressEvent(TransferCompletedEvent, tracker.completedBytes, req.ContentLength)
-	publishProgress(listener, event)
-
-	return conn.handleResponse(resp, crc)
-}
-
-func (conn Conn) getURLParams(params map[string]interface{}) string {
-	// Sort
-	keys := make([]string, 0, len(params))
-	for k := range params {
-		keys = append(keys, k)
-	}
-	sort.Strings(keys)
-
-	// Serialize
-	var buf bytes.Buffer
-	for _, k := range keys {
-		if buf.Len() > 0 {
-			buf.WriteByte('&')
-		}
-		buf.WriteString(url.QueryEscape(k))
-		if params[k] != nil {
-			buf.WriteString("=" + url.QueryEscape(params[k].(string)))
-		}
-	}
-
-	return buf.String()
-}
-
-func (conn Conn) getSubResource(params map[string]interface{}) string {
-	// Sort
-	keys := make([]string, 0, len(params))
-	for k := range params {
-		if conn.isParamSign(k) {
-			keys = append(keys, k)
-		}
-	}
-	sort.Strings(keys)
-
-	// Serialize
-	var buf bytes.Buffer
-	for _, k := range keys {
-		if buf.Len() > 0 {
-			buf.WriteByte('&')
-		}
-		buf.WriteString(k)
-		if params[k] != nil {
-			buf.WriteString("=" + params[k].(string))
-		}
-	}
-
-	return buf.String()
-}
-
-func (conn Conn) isParamSign(paramKey string) bool {
-	for _, k := range signKeyList {
-		if paramKey == k {
-			return true
-		}
-	}
-	return false
-}
-
-func (conn Conn) doRequest(method string, uri *url.URL, canonicalizedResource string, headers map[string]string,
-	data io.Reader, initCRC uint64, listener ProgressListener) (*Response, error) {
-	method = strings.ToUpper(method)
-	req := &http.Request{
-		Method:     method,
-		URL:        uri,
-		Proto:      "HTTP/1.1",
-		ProtoMajor: 1,
-		ProtoMinor: 1,
-		Header:     make(http.Header),
-		Host:       uri.Host,
-	}
-
-	tracker := &readerTracker{completedBytes: 0}
-	fd, crc := conn.handleBody(req, data, initCRC, listener, tracker)
-	if fd != nil {
-		defer func() {
-			fd.Close()
-			os.Remove(fd.Name())
-		}()
-	}
-
-	if conn.config.IsAuthProxy {
-		auth := conn.config.ProxyUser + ":" + conn.config.ProxyPassword
-		basic := "Basic " + base64.StdEncoding.EncodeToString([]byte(auth))
-		req.Header.Set("Proxy-Authorization", basic)
-	}
-
-	date := time.Now().UTC().Format(http.TimeFormat)
-	req.Header.Set(HTTPHeaderDate, date)
-	req.Header.Set(HTTPHeaderHost, conn.config.Endpoint)
-	req.Header.Set(HTTPHeaderUserAgent, conn.config.UserAgent)
-	if conn.config.SecurityToken != "" {
-		req.Header.Set(HTTPHeaderOssSecurityToken, conn.config.SecurityToken)
-	}
-
-	if headers != nil {
-		for k, v := range headers {
-			req.Header.Set(k, v)
-		}
-	}
-
-	conn.signHeader(req, canonicalizedResource)
-
-	// Transfer started
-	event := newProgressEvent(TransferStartedEvent, 0, req.ContentLength)
-	publishProgress(listener, event)
-
-	if conn.config.LogLevel >= Debug {
-		conn.LoggerHttpReq(req)
-	}
-
-	resp, err := conn.client.Do(req)
-
-	if err != nil {
-		// Transfer failed
-		event = newProgressEvent(TransferFailedEvent, tracker.completedBytes, req.ContentLength)
-		publishProgress(listener, event)
-		return nil, err
-	}
-
-	if conn.config.LogLevel >= Debug {
-		//print out http resp
-		conn.LoggerHttpResp(req, resp)
-	}
-
-	// Transfer completed
-	event = newProgressEvent(TransferCompletedEvent, tracker.completedBytes, req.ContentLength)
-	publishProgress(listener, event)
-
-	return conn.handleResponse(resp, crc)
-}
-
-func (conn Conn) signURL(method HTTPMethod, bucketName, objectName string, expiration int64, params map[string]interface{}, headers map[string]string) string {
-	if conn.config.SecurityToken != "" {
-		params[HTTPParamSecurityToken] = conn.config.SecurityToken
-	}
-	subResource := conn.getSubResource(params)
-	canonicalizedResource := conn.url.getResource(bucketName, objectName, subResource)
-
-	m := strings.ToUpper(string(method))
-	req := &http.Request{
-		Method: m,
-		Header: make(http.Header),
-	}
-
-	if conn.config.IsAuthProxy {
-		auth := conn.config.ProxyUser + ":" + conn.config.ProxyPassword
-		basic := "Basic " + base64.StdEncoding.EncodeToString([]byte(auth))
-		req.Header.Set("Proxy-Authorization", basic)
-	}
-
-	req.Header.Set(HTTPHeaderDate, strconv.FormatInt(expiration, 10))
-	req.Header.Set(HTTPHeaderHost, conn.config.Endpoint)
-	req.Header.Set(HTTPHeaderUserAgent, conn.config.UserAgent)
-
-	if headers != nil {
-		for k, v := range headers {
-			req.Header.Set(k, v)
-		}
-	}
-
-	signedStr := conn.getSignedStr(req, canonicalizedResource)
-
-	params[HTTPParamExpires] = strconv.FormatInt(expiration, 10)
-	params[HTTPParamAccessKeyID] = conn.config.AccessKeyID
-	params[HTTPParamSignature] = signedStr
-
-	urlParams := conn.getURLParams(params)
-	return conn.url.getSignURL(bucketName, objectName, urlParams)
-}
-
-func (conn Conn) signRtmpURL(bucketName, channelName, playlistName string, expiration int64) string {
-	params := map[string]interface{}{}
-	if playlistName != "" {
-		params[HTTPParamPlaylistName] = playlistName
-	}
-	expireStr := strconv.FormatInt(expiration, 10)
-	params[HTTPParamExpires] = expireStr
-
-	if conn.config.AccessKeyID != "" {
-		params[HTTPParamAccessKeyID] = conn.config.AccessKeyID
-		if conn.config.SecurityToken != "" {
-			params[HTTPParamSecurityToken] = conn.config.SecurityToken
-		}
-		signedStr := conn.getRtmpSignedStr(bucketName, channelName, playlistName, expiration, params)
-		params[HTTPParamSignature] = signedStr
-	}
-
-	urlParams := conn.getURLParams(params)
-	return conn.url.getSignRtmpURL(bucketName, channelName, urlParams)
-}
-
-// handleBody handles request body
-func (conn Conn) handleBody(req *http.Request, body io.Reader, initCRC uint64,
-	listener ProgressListener, tracker *readerTracker) (*os.File, hash.Hash64) {
-	var file *os.File
-	var crc hash.Hash64
-	reader := body
-
-	// Length
-	switch v := body.(type) {
-	case *bytes.Buffer:
-		req.ContentLength = int64(v.Len())
-	case *bytes.Reader:
-		req.ContentLength = int64(v.Len())
-	case *strings.Reader:
-		req.ContentLength = int64(v.Len())
-	case *os.File:
-		req.ContentLength = tryGetFileSize(v)
-	case *io.LimitedReader:
-		req.ContentLength = int64(v.N)
-	}
-	req.Header.Set(HTTPHeaderContentLength, strconv.FormatInt(req.ContentLength, 10))
-
-	// MD5
-	if body != nil && conn.config.IsEnableMD5 && req.Header.Get(HTTPHeaderContentMD5) == "" {
-		md5 := ""
-		reader, md5, file, _ = calcMD5(body, req.ContentLength, conn.config.MD5Threshold)
-		req.Header.Set(HTTPHeaderContentMD5, md5)
-	}
-
-	// CRC
-	if reader != nil && conn.config.IsEnableCRC {
-		crc = NewCRC(crcTable(), initCRC)
-		reader = TeeReader(reader, crc, req.ContentLength, listener, tracker)
-	}
-
-	// HTTP body
-	rc, ok := reader.(io.ReadCloser)
-	if !ok && reader != nil {
-		rc = ioutil.NopCloser(reader)
-	}
-
-	if conn.isUploadLimitReq(req) {
-		limitReader := &LimitSpeedReader{
-			reader:     rc,
-			ossLimiter: conn.config.UploadLimiter,
-		}
-		req.Body = limitReader
-	} else {
-		req.Body = rc
-	}
-	return file, crc
-}
-
-// isUploadLimitReq: judge limit upload speed or not
-func (conn Conn) isUploadLimitReq(req *http.Request) bool {
-	if conn.config.UploadLimitSpeed == 0 || conn.config.UploadLimiter == nil {
-		return false
-	}
-
-	if req.Method != "GET" && req.Method != "DELETE" && req.Method != "HEAD" {
-		if req.ContentLength > 0 {
-			return true
-		}
-	}
-	return false
-}
-
-func tryGetFileSize(f *os.File) int64 {
-	fInfo, _ := f.Stat()
-	return fInfo.Size()
-}
-
-// handleResponse handles response
-func (conn Conn) handleResponse(resp *http.Response, crc hash.Hash64) (*Response, error) {
-	var cliCRC uint64
-	var srvCRC uint64
-
-	statusCode := resp.StatusCode
-	if statusCode >= 400 && statusCode <= 505 {
-		// 4xx and 5xx indicate that the operation has error occurred
-		var respBody []byte
-		respBody, err := readResponseBody(resp)
-		if err != nil {
-			return nil, err
-		}
-
-		if len(respBody) == 0 {
-			err = ServiceError{
-				StatusCode: statusCode,
-				RequestID:  resp.Header.Get(HTTPHeaderOssRequestID),
-			}
-		} else {
-			// Response contains storage service error object, unmarshal
-			srvErr, errIn := serviceErrFromXML(respBody, resp.StatusCode,
-				resp.Header.Get(HTTPHeaderOssRequestID))
-			if errIn != nil { // error unmarshaling the error response
-				err = fmt.Errorf("oss: service returned invalid response body, status = %s, RequestId = %s", resp.Status, resp.Header.Get(HTTPHeaderOssRequestID))
-			} else {
-				err = srvErr
-			}
-		}
-
-		return &Response{
-			StatusCode: resp.StatusCode,
-			Headers:    resp.Header,
-			Body:       ioutil.NopCloser(bytes.NewReader(respBody)), // restore the body
-		}, err
-	} else if statusCode >= 300 && statusCode <= 307 {
-		// OSS use 3xx, but response has no body
-		err := fmt.Errorf("oss: service returned %d,%s", resp.StatusCode, resp.Status)
-		return &Response{
-			StatusCode: resp.StatusCode,
-			Headers:    resp.Header,
-			Body:       resp.Body,
-		}, err
-	}
-
-	if conn.config.IsEnableCRC && crc != nil {
-		cliCRC = crc.Sum64()
-	}
-	srvCRC, _ = strconv.ParseUint(resp.Header.Get(HTTPHeaderOssCRC64), 10, 64)
-
-	// 2xx, successful
-	return &Response{
-		StatusCode: resp.StatusCode,
-		Headers:    resp.Header,
-		Body:       resp.Body,
-		ClientCRC:  cliCRC,
-		ServerCRC:  srvCRC,
-	}, nil
-}
-
-func (conn Conn) LoggerHttpReq(req *http.Request) {
-	var logBuffer bytes.Buffer
-	logBuffer.WriteString(fmt.Sprintf("[Req:%p]Method:%s\t", req, req.Method))
-	logBuffer.WriteString(fmt.Sprintf("Host:%s\t", req.URL.Host))
-	logBuffer.WriteString(fmt.Sprintf("Path:%s\t", req.URL.Path))
-	logBuffer.WriteString(fmt.Sprintf("Query:%s\t", req.URL.RawQuery))
-	logBuffer.WriteString(fmt.Sprintf("Header info:"))
-
-	for k, v := range req.Header {
-		var valueBuffer bytes.Buffer
-		for j := 0; j < len(v); j++ {
-			if j > 0 {
-				valueBuffer.WriteString(" ")
-			}
-			valueBuffer.WriteString(v[j])
-		}
-		logBuffer.WriteString(fmt.Sprintf("\t%s:%s", k, valueBuffer.String()))
-	}
-	conn.config.WriteLog(Debug, "%s\n", logBuffer.String())
-}
-
-func (conn Conn) LoggerHttpResp(req *http.Request, resp *http.Response) {
-	var logBuffer bytes.Buffer
-	logBuffer.WriteString(fmt.Sprintf("[Resp:%p]StatusCode:%d\t", req, resp.StatusCode))
-	logBuffer.WriteString(fmt.Sprintf("Header info:"))
-	for k, v := range resp.Header {
-		var valueBuffer bytes.Buffer
-		for j := 0; j < len(v); j++ {
-			if j > 0 {
-				valueBuffer.WriteString(" ")
-			}
-			valueBuffer.WriteString(v[j])
-		}
-		logBuffer.WriteString(fmt.Sprintf("\t%s:%s", k, valueBuffer.String()))
-	}
-	conn.config.WriteLog(Debug, "%s\n", logBuffer.String())
-}
-
-func calcMD5(body io.Reader, contentLen, md5Threshold int64) (reader io.Reader, b64 string, tempFile *os.File, err error) {
-	if contentLen == 0 || contentLen > md5Threshold {
-		// Huge body, use temporary file
-		tempFile, err = ioutil.TempFile(os.TempDir(), TempFilePrefix)
-		if tempFile != nil {
-			io.Copy(tempFile, body)
-			tempFile.Seek(0, os.SEEK_SET)
-			md5 := md5.New()
-			io.Copy(md5, tempFile)
-			sum := md5.Sum(nil)
-			b64 = base64.StdEncoding.EncodeToString(sum[:])
-			tempFile.Seek(0, os.SEEK_SET)
-			reader = tempFile
-		}
-	} else {
-		// Small body, use memory
-		buf, _ := ioutil.ReadAll(body)
-		sum := md5.Sum(buf)
-		b64 = base64.StdEncoding.EncodeToString(sum[:])
-		reader = bytes.NewReader(buf)
-	}
-	return
-}
-
-func readResponseBody(resp *http.Response) ([]byte, error) {
-	defer resp.Body.Close()
-	out, err := ioutil.ReadAll(resp.Body)
-	if err == io.EOF {
-		err = nil
-	}
-	return out, err
-}
-
-func serviceErrFromXML(body []byte, statusCode int, requestID string) (ServiceError, error) {
-	var storageErr ServiceError
-
-	if err := xml.Unmarshal(body, &storageErr); err != nil {
-		return storageErr, err
-	}
-
-	storageErr.StatusCode = statusCode
-	storageErr.RequestID = requestID
-	storageErr.RawMessage = string(body)
-	return storageErr, nil
-}
-
-func xmlUnmarshal(body io.Reader, v interface{}) error {
-	data, err := ioutil.ReadAll(body)
-	if err != nil {
-		return err
-	}
-	return xml.Unmarshal(data, v)
-}
-
-func jsonUnmarshal(body io.Reader, v interface{}) error {
-	data, err := ioutil.ReadAll(body)
-	if err != nil {
-		return err
-	}
-	return json.Unmarshal(data, v)
-}
-
-// timeoutConn handles HTTP timeout
-type timeoutConn struct {
-	conn        net.Conn
-	timeout     time.Duration
-	longTimeout time.Duration
-}
-
-func newTimeoutConn(conn net.Conn, timeout time.Duration, longTimeout time.Duration) *timeoutConn {
-	conn.SetReadDeadline(time.Now().Add(longTimeout))
-	return &timeoutConn{
-		conn:        conn,
-		timeout:     timeout,
-		longTimeout: longTimeout,
-	}
-}
-
-func (c *timeoutConn) Read(b []byte) (n int, err error) {
-	c.SetReadDeadline(time.Now().Add(c.timeout))
-	n, err = c.conn.Read(b)
-	c.SetReadDeadline(time.Now().Add(c.longTimeout))
-	return n, err
-}
-
-func (c *timeoutConn) Write(b []byte) (n int, err error) {
-	c.SetWriteDeadline(time.Now().Add(c.timeout))
-	n, err = c.conn.Write(b)
-	c.SetReadDeadline(time.Now().Add(c.longTimeout))
-	return n, err
-}
-
-func (c *timeoutConn) Close() error {
-	return c.conn.Close()
-}
-
-func (c *timeoutConn) LocalAddr() net.Addr {
-	return c.conn.LocalAddr()
-}
-
-func (c *timeoutConn) RemoteAddr() net.Addr {
-	return c.conn.RemoteAddr()
-}
-
-func (c *timeoutConn) SetDeadline(t time.Time) error {
-	return c.conn.SetDeadline(t)
-}
-
-func (c *timeoutConn) SetReadDeadline(t time.Time) error {
-	return c.conn.SetReadDeadline(t)
-}
-
-func (c *timeoutConn) SetWriteDeadline(t time.Time) error {
-	return c.conn.SetWriteDeadline(t)
-}
-
-// UrlMaker builds URL and resource
-const (
-	urlTypeCname  = 1
-	urlTypeIP     = 2
-	urlTypeAliyun = 3
-)
-
-type urlMaker struct {
-	Scheme  string // HTTP or HTTPS
-	NetLoc  string // Host or IP
-	Type    int    // 1 CNAME, 2 IP, 3 ALIYUN
-	IsProxy bool   // Proxy
-}
-
-// Init parses endpoint
-func (um *urlMaker) Init(endpoint string, isCname bool, isProxy bool) {
-	if strings.HasPrefix(endpoint, "http://") {
-		um.Scheme = "http"
-		um.NetLoc = endpoint[len("http://"):]
-	} else if strings.HasPrefix(endpoint, "https://") {
-		um.Scheme = "https"
-		um.NetLoc = endpoint[len("https://"):]
-	} else {
-		um.Scheme = "http"
-		um.NetLoc = endpoint
-	}
-
-	host, _, err := net.SplitHostPort(um.NetLoc)
-	if err != nil {
-		host = um.NetLoc
-		if host[0] == '[' && host[len(host)-1] == ']' {
-			host = host[1 : len(host)-1]
-		}
-	}
-
-	ip := net.ParseIP(host)
-	if ip != nil {
-		um.Type = urlTypeIP
-	} else if isCname {
-		um.Type = urlTypeCname
-	} else {
-		um.Type = urlTypeAliyun
-	}
-	um.IsProxy = isProxy
-}
-
-// getURL gets URL
-func (um urlMaker) getURL(bucket, object, params string) *url.URL {
-	host, path := um.buildURL(bucket, object)
-	addr := ""
-	if params == "" {
-		addr = fmt.Sprintf("%s://%s%s", um.Scheme, host, path)
-	} else {
-		addr = fmt.Sprintf("%s://%s%s?%s", um.Scheme, host, path, params)
-	}
-	uri, _ := url.ParseRequestURI(addr)
-	return uri
-}
-
-// getSignURL gets sign URL
-func (um urlMaker) getSignURL(bucket, object, params string) string {
-	host, path := um.buildURL(bucket, object)
-	return fmt.Sprintf("%s://%s%s?%s", um.Scheme, host, path, params)
-}
-
-// getSignRtmpURL Build Sign Rtmp URL
-func (um urlMaker) getSignRtmpURL(bucket, channelName, params string) string {
-	host, path := um.buildURL(bucket, "live")
-
-	channelName = url.QueryEscape(channelName)
-	channelName = strings.Replace(channelName, "+", "%20", -1)
-
-	return fmt.Sprintf("rtmp://%s%s/%s?%s", host, path, channelName, params)
-}
-
-// buildURL builds URL
-func (um urlMaker) buildURL(bucket, object string) (string, string) {
-	var host = ""
-	var path = ""
-
-	object = url.QueryEscape(object)
-	object = strings.Replace(object, "+", "%20", -1)
-
-	if um.Type == urlTypeCname {
-		host = um.NetLoc
-		path = "/" + object
-	} else if um.Type == urlTypeIP {
-		if bucket == "" {
-			host = um.NetLoc
-			path = "/"
-		} else {
-			host = um.NetLoc
-			path = fmt.Sprintf("/%s/%s", bucket, object)
-		}
-	} else {
-		if bucket == "" {
-			host = um.NetLoc
-			path = "/"
-		} else {
-			host = bucket + "." + um.NetLoc
-			path = "/" + object
-		}
-	}
-
-	return host, path
-}
-
-// getResource gets canonicalized resource
-func (um urlMaker) getResource(bucketName, objectName, subResource string) string {
-	if subResource != "" {
-		subResource = "?" + subResource
-	}
-	if bucketName == "" {
-		return fmt.Sprintf("/%s%s", bucketName, subResource)
-	}
-	return fmt.Sprintf("/%s/%s%s", bucketName, objectName, subResource)
-}

+ 0 - 146
vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/const.go

@@ -1,146 +0,0 @@
-package oss
-
-import "os"
-
-// ACLType bucket/object ACL
-type ACLType string
-
-const (
-	// ACLPrivate definition : private read and write
-	ACLPrivate ACLType = "private"
-
-	// ACLPublicRead definition : public read and private write
-	ACLPublicRead ACLType = "public-read"
-
-	// ACLPublicReadWrite definition : public read and public write
-	ACLPublicReadWrite ACLType = "public-read-write"
-
-	// ACLDefault Object. It's only applicable for object.
-	ACLDefault ACLType = "default"
-)
-
-// MetadataDirectiveType specifying whether use the metadata of source object when copying object.
-type MetadataDirectiveType string
-
-const (
-	// MetaCopy the target object's metadata is copied from the source one
-	MetaCopy MetadataDirectiveType = "COPY"
-
-	// MetaReplace the target object's metadata is created as part of the copy request (not same as the source one)
-	MetaReplace MetadataDirectiveType = "REPLACE"
-)
-
-// StorageClassType bucket storage type
-type StorageClassType string
-
-const (
-	// StorageStandard standard
-	StorageStandard StorageClassType = "Standard"
-
-	// StorageIA infrequent access
-	StorageIA StorageClassType = "IA"
-
-	// StorageArchive archive
-	StorageArchive StorageClassType = "Archive"
-)
-
-// PayerType the type of request payer
-type PayerType string
-
-const (
-	// Requester the requester who send the request
-	Requester PayerType = "requester"
-)
-
-// HTTPMethod HTTP request method
-type HTTPMethod string
-
-const (
-	// HTTPGet HTTP GET
-	HTTPGet HTTPMethod = "GET"
-
-	// HTTPPut HTTP PUT
-	HTTPPut HTTPMethod = "PUT"
-
-	// HTTPHead HTTP HEAD
-	HTTPHead HTTPMethod = "HEAD"
-
-	// HTTPPost HTTP POST
-	HTTPPost HTTPMethod = "POST"
-
-	// HTTPDelete HTTP DELETE
-	HTTPDelete HTTPMethod = "DELETE"
-)
-
-// HTTP headers
-const (
-	HTTPHeaderAcceptEncoding     string = "Accept-Encoding"
-	HTTPHeaderAuthorization             = "Authorization"
-	HTTPHeaderCacheControl              = "Cache-Control"
-	HTTPHeaderContentDisposition        = "Content-Disposition"
-	HTTPHeaderContentEncoding           = "Content-Encoding"
-	HTTPHeaderContentLength             = "Content-Length"
-	HTTPHeaderContentMD5                = "Content-MD5"
-	HTTPHeaderContentType               = "Content-Type"
-	HTTPHeaderContentLanguage           = "Content-Language"
-	HTTPHeaderDate                      = "Date"
-	HTTPHeaderEtag                      = "ETag"
-	HTTPHeaderExpires                   = "Expires"
-	HTTPHeaderHost                      = "Host"
-	HTTPHeaderLastModified              = "Last-Modified"
-	HTTPHeaderRange                     = "Range"
-	HTTPHeaderLocation                  = "Location"
-	HTTPHeaderOrigin                    = "Origin"
-	HTTPHeaderServer                    = "Server"
-	HTTPHeaderUserAgent                 = "User-Agent"
-	HTTPHeaderIfModifiedSince           = "If-Modified-Since"
-	HTTPHeaderIfUnmodifiedSince         = "If-Unmodified-Since"
-	HTTPHeaderIfMatch                   = "If-Match"
-	HTTPHeaderIfNoneMatch               = "If-None-Match"
-
-	HTTPHeaderOssACL                         = "X-Oss-Acl"
-	HTTPHeaderOssMetaPrefix                  = "X-Oss-Meta-"
-	HTTPHeaderOssObjectACL                   = "X-Oss-Object-Acl"
-	HTTPHeaderOssSecurityToken               = "X-Oss-Security-Token"
-	HTTPHeaderOssServerSideEncryption        = "X-Oss-Server-Side-Encryption"
-	HTTPHeaderOssServerSideEncryptionKeyID   = "X-Oss-Server-Side-Encryption-Key-Id"
-	HTTPHeaderOssCopySource                  = "X-Oss-Copy-Source"
-	HTTPHeaderOssCopySourceRange             = "X-Oss-Copy-Source-Range"
-	HTTPHeaderOssCopySourceIfMatch           = "X-Oss-Copy-Source-If-Match"
-	HTTPHeaderOssCopySourceIfNoneMatch       = "X-Oss-Copy-Source-If-None-Match"
-	HTTPHeaderOssCopySourceIfModifiedSince   = "X-Oss-Copy-Source-If-Modified-Since"
-	HTTPHeaderOssCopySourceIfUnmodifiedSince = "X-Oss-Copy-Source-If-Unmodified-Since"
-	HTTPHeaderOssMetadataDirective           = "X-Oss-Metadata-Directive"
-	HTTPHeaderOssNextAppendPosition          = "X-Oss-Next-Append-Position"
-	HTTPHeaderOssRequestID                   = "X-Oss-Request-Id"
-	HTTPHeaderOssCRC64                       = "X-Oss-Hash-Crc64ecma"
-	HTTPHeaderOssSymlinkTarget               = "X-Oss-Symlink-Target"
-	HTTPHeaderOssStorageClass                = "X-Oss-Storage-Class"
-	HTTPHeaderOssCallback                    = "X-Oss-Callback"
-	HTTPHeaderOssCallbackVar                 = "X-Oss-Callback-Var"
-	HTTPHeaderOSSRequester                   = "X-Oss-Request-Payer"
-)
-
-// HTTP Param
-const (
-	HTTPParamExpires       = "Expires"
-	HTTPParamAccessKeyID   = "OSSAccessKeyId"
-	HTTPParamSignature     = "Signature"
-	HTTPParamSecurityToken = "security-token"
-	HTTPParamPlaylistName  = "playlistName"
-)
-
-// Other constants
-const (
-	MaxPartSize = 5 * 1024 * 1024 * 1024 // Max part size, 5GB
-	MinPartSize = 100 * 1024             // Min part size, 100KB
-
-	FilePermMode = os.FileMode(0664) // Default file permission
-
-	TempFilePrefix = "oss-go-temp-" // Temp file prefix
-	TempFileSuffix = ".temp"        // Temp file suffix
-
-	CheckpointFileSuffix = ".cp" // Checkpoint file suffix
-
-	Version = "1.9.5" // Go SDK version
-)

+ 0 - 123
vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/crc.go

@@ -1,123 +0,0 @@
-package oss
-
-import (
-	"hash"
-	"hash/crc64"
-)
-
-// digest represents the partial evaluation of a checksum.
-type digest struct {
-	crc uint64
-	tab *crc64.Table
-}
-
-// NewCRC creates a new hash.Hash64 computing the CRC64 checksum
-// using the polynomial represented by the Table.
-func NewCRC(tab *crc64.Table, init uint64) hash.Hash64 { return &digest{init, tab} }
-
-// Size returns the number of bytes sum will return.
-func (d *digest) Size() int { return crc64.Size }
-
-// BlockSize returns the hash's underlying block size.
-// The Write method must be able to accept any amount
-// of data, but it may operate more efficiently if all writes
-// are a multiple of the block size.
-func (d *digest) BlockSize() int { return 1 }
-
-// Reset resets the hash to its initial state.
-func (d *digest) Reset() { d.crc = 0 }
-
-// Write (via the embedded io.Writer interface) adds more data to the running hash.
-// It never returns an error.
-func (d *digest) Write(p []byte) (n int, err error) {
-	d.crc = crc64.Update(d.crc, d.tab, p)
-	return len(p), nil
-}
-
-// Sum64 returns CRC64 value.
-func (d *digest) Sum64() uint64 { return d.crc }
-
-// Sum returns hash value.
-func (d *digest) Sum(in []byte) []byte {
-	s := d.Sum64()
-	return append(in, byte(s>>56), byte(s>>48), byte(s>>40), byte(s>>32), byte(s>>24), byte(s>>16), byte(s>>8), byte(s))
-}
-
-// gf2Dim dimension of GF(2) vectors (length of CRC)
-const gf2Dim int = 64
-
-func gf2MatrixTimes(mat []uint64, vec uint64) uint64 {
-	var sum uint64
-	for i := 0; vec != 0; i++ {
-		if vec&1 != 0 {
-			sum ^= mat[i]
-		}
-
-		vec >>= 1
-	}
-	return sum
-}
-
-func gf2MatrixSquare(square []uint64, mat []uint64) {
-	for n := 0; n < gf2Dim; n++ {
-		square[n] = gf2MatrixTimes(mat, mat[n])
-	}
-}
-
-// CRC64Combine combines CRC64
-func CRC64Combine(crc1 uint64, crc2 uint64, len2 uint64) uint64 {
-	var even [gf2Dim]uint64 // Even-power-of-two zeros operator
-	var odd [gf2Dim]uint64  // Odd-power-of-two zeros operator
-
-	// Degenerate case
-	if len2 == 0 {
-		return crc1
-	}
-
-	// Put operator for one zero bit in odd
-	odd[0] = crc64.ECMA // CRC64 polynomial
-	var row uint64 = 1
-	for n := 1; n < gf2Dim; n++ {
-		odd[n] = row
-		row <<= 1
-	}
-
-	// Put operator for two zero bits in even
-	gf2MatrixSquare(even[:], odd[:])
-
-	// Put operator for four zero bits in odd
-	gf2MatrixSquare(odd[:], even[:])
-
-	// Apply len2 zeros to crc1, first square will put the operator for one zero byte, eight zero bits, in even
-	for {
-		// Apply zeros operator for this bit of len2
-		gf2MatrixSquare(even[:], odd[:])
-
-		if len2&1 != 0 {
-			crc1 = gf2MatrixTimes(even[:], crc1)
-		}
-
-		len2 >>= 1
-
-		// If no more bits set, then done
-		if len2 == 0 {
-			break
-		}
-
-		// Another iteration of the loop with odd and even swapped
-		gf2MatrixSquare(odd[:], even[:])
-		if len2&1 != 0 {
-			crc1 = gf2MatrixTimes(odd[:], crc1)
-		}
-		len2 >>= 1
-
-		// If no more bits set, then done
-		if len2 == 0 {
-			break
-		}
-	}
-
-	// Return combined CRC
-	crc1 ^= crc2
-	return crc1
-}

+ 0 - 568
vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/download.go

@@ -1,568 +0,0 @@
-package oss
-
-import (
-	"crypto/md5"
-	"encoding/base64"
-	"encoding/json"
-	"errors"
-	"fmt"
-	"hash"
-	"hash/crc64"
-	"io"
-	"io/ioutil"
-	"net/http"
-	"os"
-	"path/filepath"
-	"strconv"
-)
-
-// DownloadFile downloads files with multipart download.
-//
-// objectKey    the object key.
-// filePath    the local file to download from objectKey in OSS.
-// partSize    the part size in bytes.
-// options    object's constraints, check out GetObject for the reference.
-//
-// error    it's nil when the call succeeds, otherwise it's an error object.
-//
-func (bucket Bucket) DownloadFile(objectKey, filePath string, partSize int64, options ...Option) error {
-	if partSize < 1 {
-		return errors.New("oss: part size smaller than 1")
-	}
-
-	uRange, err := getRangeConfig(options)
-	if err != nil {
-		return err
-	}
-
-	cpConf := getCpConfig(options)
-	routines := getRoutines(options)
-
-	if cpConf != nil && cpConf.IsEnable {
-		cpFilePath := getDownloadCpFilePath(cpConf, bucket.BucketName, objectKey, filePath)
-		if cpFilePath != "" {
-			return bucket.downloadFileWithCp(objectKey, filePath, partSize, options, cpFilePath, routines, uRange)
-		}
-	}
-
-	return bucket.downloadFile(objectKey, filePath, partSize, options, routines, uRange)
-}
-
-func getDownloadCpFilePath(cpConf *cpConfig, srcBucket, srcObject, destFile string) string {
-	if cpConf.FilePath == "" && cpConf.DirPath != "" {
-		src := fmt.Sprintf("oss://%v/%v", srcBucket, srcObject)
-		absPath, _ := filepath.Abs(destFile)
-		cpFileName := getCpFileName(src, absPath)
-		cpConf.FilePath = cpConf.DirPath + string(os.PathSeparator) + cpFileName
-	}
-	return cpConf.FilePath
-}
-
-// getRangeConfig gets the download range from the options.
-func getRangeConfig(options []Option) (*unpackedRange, error) {
-	rangeOpt, err := findOption(options, HTTPHeaderRange, nil)
-	if err != nil || rangeOpt == nil {
-		return nil, err
-	}
-	return parseRange(rangeOpt.(string))
-}
-
-// ----- concurrent download without checkpoint  -----
-
-// downloadWorkerArg is download worker's parameters
-type downloadWorkerArg struct {
-	bucket    *Bucket
-	key       string
-	filePath  string
-	options   []Option
-	hook      downloadPartHook
-	enableCRC bool
-}
-
-// downloadPartHook is hook for test
-type downloadPartHook func(part downloadPart) error
-
-var downloadPartHooker downloadPartHook = defaultDownloadPartHook
-
-func defaultDownloadPartHook(part downloadPart) error {
-	return nil
-}
-
-// defaultDownloadProgressListener defines default ProgressListener, shields the ProgressListener in options of GetObject.
-type defaultDownloadProgressListener struct {
-}
-
-// ProgressChanged no-ops
-func (listener *defaultDownloadProgressListener) ProgressChanged(event *ProgressEvent) {
-}
-
-// downloadWorker
-func downloadWorker(id int, arg downloadWorkerArg, jobs <-chan downloadPart, results chan<- downloadPart, failed chan<- error, die <-chan bool) {
-	for part := range jobs {
-		if err := arg.hook(part); err != nil {
-			failed <- err
-			break
-		}
-
-		// Resolve options
-		r := Range(part.Start, part.End)
-		p := Progress(&defaultDownloadProgressListener{})
-		opts := make([]Option, len(arg.options)+2)
-		// Append orderly, can not be reversed!
-		opts = append(opts, arg.options...)
-		opts = append(opts, r, p)
-
-		rd, err := arg.bucket.GetObject(arg.key, opts...)
-		if err != nil {
-			failed <- err
-			break
-		}
-		defer rd.Close()
-
-		var crcCalc hash.Hash64
-		if arg.enableCRC {
-			crcCalc = crc64.New(crcTable())
-			contentLen := part.End - part.Start + 1
-			rd = ioutil.NopCloser(TeeReader(rd, crcCalc, contentLen, nil, nil))
-		}
-		defer rd.Close()
-
-		select {
-		case <-die:
-			return
-		default:
-		}
-
-		fd, err := os.OpenFile(arg.filePath, os.O_WRONLY, FilePermMode)
-		if err != nil {
-			failed <- err
-			break
-		}
-
-		_, err = fd.Seek(part.Start-part.Offset, os.SEEK_SET)
-		if err != nil {
-			fd.Close()
-			failed <- err
-			break
-		}
-
-		_, err = io.Copy(fd, rd)
-		if err != nil {
-			fd.Close()
-			failed <- err
-			break
-		}
-
-		if arg.enableCRC {
-			part.CRC64 = crcCalc.Sum64()
-		}
-
-		fd.Close()
-		results <- part
-	}
-}
-
-// downloadScheduler
-func downloadScheduler(jobs chan downloadPart, parts []downloadPart) {
-	for _, part := range parts {
-		jobs <- part
-	}
-	close(jobs)
-}
-
-// downloadPart defines download part
-type downloadPart struct {
-	Index  int    // Part number, starting from 0
-	Start  int64  // Start index
-	End    int64  // End index
-	Offset int64  // Offset
-	CRC64  uint64 // CRC check value of part
-}
-
-// getDownloadParts gets download parts
-func getDownloadParts(objectSize, partSize int64, uRange *unpackedRange) []downloadPart {
-	parts := []downloadPart{}
-	part := downloadPart{}
-	i := 0
-	start, end := adjustRange(uRange, objectSize)
-	for offset := start; offset < end; offset += partSize {
-		part.Index = i
-		part.Start = offset
-		part.End = GetPartEnd(offset, end, partSize)
-		part.Offset = start
-		part.CRC64 = 0
-		parts = append(parts, part)
-		i++
-	}
-	return parts
-}
-
-// getObjectBytes gets object bytes length
-func getObjectBytes(parts []downloadPart) int64 {
-	var ob int64
-	for _, part := range parts {
-		ob += (part.End - part.Start + 1)
-	}
-	return ob
-}
-
-// combineCRCInParts caculates the total CRC of continuous parts
-func combineCRCInParts(dps []downloadPart) uint64 {
-	if dps == nil || len(dps) == 0 {
-		return 0
-	}
-
-	crc := dps[0].CRC64
-	for i := 1; i < len(dps); i++ {
-		crc = CRC64Combine(crc, dps[i].CRC64, (uint64)(dps[i].End-dps[i].Start+1))
-	}
-
-	return crc
-}
-
-// downloadFile downloads file concurrently without checkpoint.
-func (bucket Bucket) downloadFile(objectKey, filePath string, partSize int64, options []Option, routines int, uRange *unpackedRange) error {
-	tempFilePath := filePath + TempFileSuffix
-	listener := getProgressListener(options)
-
-	payerOptions := []Option{}
-	payer := getPayer(options)
-	if payer != "" {
-		payerOptions = append(payerOptions, RequestPayer(PayerType(payer)))
-	}
-
-	// If the file does not exist, create one. If exists, the download will overwrite it.
-	fd, err := os.OpenFile(tempFilePath, os.O_WRONLY|os.O_CREATE, FilePermMode)
-	if err != nil {
-		return err
-	}
-	fd.Close()
-
-	meta, err := bucket.GetObjectDetailedMeta(objectKey, payerOptions...)
-	if err != nil {
-		return err
-	}
-
-	objectSize, err := strconv.ParseInt(meta.Get(HTTPHeaderContentLength), 10, 0)
-	if err != nil {
-		return err
-	}
-
-	enableCRC := false
-	expectedCRC := (uint64)(0)
-	if bucket.getConfig().IsEnableCRC && meta.Get(HTTPHeaderOssCRC64) != "" {
-		if uRange == nil || (!uRange.hasStart && !uRange.hasEnd) {
-			enableCRC = true
-			expectedCRC, _ = strconv.ParseUint(meta.Get(HTTPHeaderOssCRC64), 10, 0)
-		}
-	}
-
-	// Get the parts of the file
-	parts := getDownloadParts(objectSize, partSize, uRange)
-	jobs := make(chan downloadPart, len(parts))
-	results := make(chan downloadPart, len(parts))
-	failed := make(chan error)
-	die := make(chan bool)
-
-	var completedBytes int64
-	totalBytes := getObjectBytes(parts)
-	event := newProgressEvent(TransferStartedEvent, 0, totalBytes)
-	publishProgress(listener, event)
-
-	// Start the download workers
-	arg := downloadWorkerArg{&bucket, objectKey, tempFilePath, options, downloadPartHooker, enableCRC}
-	for w := 1; w <= routines; w++ {
-		go downloadWorker(w, arg, jobs, results, failed, die)
-	}
-
-	// Download parts concurrently
-	go downloadScheduler(jobs, parts)
-
-	// Waiting for parts download finished
-	completed := 0
-	for completed < len(parts) {
-		select {
-		case part := <-results:
-			completed++
-			completedBytes += (part.End - part.Start + 1)
-			parts[part.Index].CRC64 = part.CRC64
-			event = newProgressEvent(TransferDataEvent, completedBytes, totalBytes)
-			publishProgress(listener, event)
-		case err := <-failed:
-			close(die)
-			event = newProgressEvent(TransferFailedEvent, completedBytes, totalBytes)
-			publishProgress(listener, event)
-			return err
-		}
-
-		if completed >= len(parts) {
-			break
-		}
-	}
-
-	event = newProgressEvent(TransferCompletedEvent, completedBytes, totalBytes)
-	publishProgress(listener, event)
-
-	if enableCRC {
-		actualCRC := combineCRCInParts(parts)
-		err = checkDownloadCRC(actualCRC, expectedCRC)
-		if err != nil {
-			return err
-		}
-	}
-
-	return os.Rename(tempFilePath, filePath)
-}
-
-// ----- Concurrent download with chcekpoint  -----
-
-const downloadCpMagic = "92611BED-89E2-46B6-89E5-72F273D4B0A3"
-
-type downloadCheckpoint struct {
-	Magic     string         // Magic
-	MD5       string         // Checkpoint content MD5
-	FilePath  string         // Local file
-	Object    string         // Key
-	ObjStat   objectStat     // Object status
-	Parts     []downloadPart // All download parts
-	PartStat  []bool         // Parts' download status
-	Start     int64          // Start point of the file
-	End       int64          // End point of the file
-	enableCRC bool           // Whether has CRC check
-	CRC       uint64         // CRC check value
-}
-
-type objectStat struct {
-	Size         int64  // Object size
-	LastModified string // Last modified time
-	Etag         string // Etag
-}
-
-// isValid flags of checkpoint data is valid. It returns true when the data is valid and the checkpoint is valid and the object is not updated.
-func (cp downloadCheckpoint) isValid(meta http.Header, uRange *unpackedRange) (bool, error) {
-	// Compare the CP's Magic and the MD5
-	cpb := cp
-	cpb.MD5 = ""
-	js, _ := json.Marshal(cpb)
-	sum := md5.Sum(js)
-	b64 := base64.StdEncoding.EncodeToString(sum[:])
-
-	if cp.Magic != downloadCpMagic || b64 != cp.MD5 {
-		return false, nil
-	}
-
-	objectSize, err := strconv.ParseInt(meta.Get(HTTPHeaderContentLength), 10, 0)
-	if err != nil {
-		return false, err
-	}
-
-	// Compare the object size, last modified time and etag
-	if cp.ObjStat.Size != objectSize ||
-		cp.ObjStat.LastModified != meta.Get(HTTPHeaderLastModified) ||
-		cp.ObjStat.Etag != meta.Get(HTTPHeaderEtag) {
-		return false, nil
-	}
-
-	// Check the download range
-	if uRange != nil {
-		start, end := adjustRange(uRange, objectSize)
-		if start != cp.Start || end != cp.End {
-			return false, nil
-		}
-	}
-
-	return true, nil
-}
-
-// load checkpoint from local file
-func (cp *downloadCheckpoint) load(filePath string) error {
-	contents, err := ioutil.ReadFile(filePath)
-	if err != nil {
-		return err
-	}
-
-	err = json.Unmarshal(contents, cp)
-	return err
-}
-
-// dump funciton dumps to file
-func (cp *downloadCheckpoint) dump(filePath string) error {
-	bcp := *cp
-
-	// Calculate MD5
-	bcp.MD5 = ""
-	js, err := json.Marshal(bcp)
-	if err != nil {
-		return err
-	}
-	sum := md5.Sum(js)
-	b64 := base64.StdEncoding.EncodeToString(sum[:])
-	bcp.MD5 = b64
-
-	// Serialize
-	js, err = json.Marshal(bcp)
-	if err != nil {
-		return err
-	}
-
-	// Dump
-	return ioutil.WriteFile(filePath, js, FilePermMode)
-}
-
-// todoParts gets unfinished parts
-func (cp downloadCheckpoint) todoParts() []downloadPart {
-	dps := []downloadPart{}
-	for i, ps := range cp.PartStat {
-		if !ps {
-			dps = append(dps, cp.Parts[i])
-		}
-	}
-	return dps
-}
-
-// getCompletedBytes gets completed size
-func (cp downloadCheckpoint) getCompletedBytes() int64 {
-	var completedBytes int64
-	for i, part := range cp.Parts {
-		if cp.PartStat[i] {
-			completedBytes += (part.End - part.Start + 1)
-		}
-	}
-	return completedBytes
-}
-
-// prepare initiates download tasks
-func (cp *downloadCheckpoint) prepare(meta http.Header, bucket *Bucket, objectKey, filePath string, partSize int64, uRange *unpackedRange) error {
-	// CP
-	cp.Magic = downloadCpMagic
-	cp.FilePath = filePath
-	cp.Object = objectKey
-
-	objectSize, err := strconv.ParseInt(meta.Get(HTTPHeaderContentLength), 10, 0)
-	if err != nil {
-		return err
-	}
-
-	cp.ObjStat.Size = objectSize
-	cp.ObjStat.LastModified = meta.Get(HTTPHeaderLastModified)
-	cp.ObjStat.Etag = meta.Get(HTTPHeaderEtag)
-
-	if bucket.getConfig().IsEnableCRC && meta.Get(HTTPHeaderOssCRC64) != "" {
-		if uRange == nil || (!uRange.hasStart && !uRange.hasEnd) {
-			cp.enableCRC = true
-			cp.CRC, _ = strconv.ParseUint(meta.Get(HTTPHeaderOssCRC64), 10, 0)
-		}
-	}
-
-	// Parts
-	cp.Parts = getDownloadParts(objectSize, partSize, uRange)
-	cp.PartStat = make([]bool, len(cp.Parts))
-	for i := range cp.PartStat {
-		cp.PartStat[i] = false
-	}
-
-	return nil
-}
-
-func (cp *downloadCheckpoint) complete(cpFilePath, downFilepath string) error {
-	os.Remove(cpFilePath)
-	return os.Rename(downFilepath, cp.FilePath)
-}
-
-// downloadFileWithCp downloads files with checkpoint.
-func (bucket Bucket) downloadFileWithCp(objectKey, filePath string, partSize int64, options []Option, cpFilePath string, routines int, uRange *unpackedRange) error {
-	tempFilePath := filePath + TempFileSuffix
-	listener := getProgressListener(options)
-
-	payerOptions := []Option{}
-	payer := getPayer(options)
-	if payer != "" {
-		payerOptions = append(payerOptions, RequestPayer(PayerType(payer)))
-	}
-
-	// Load checkpoint data.
-	dcp := downloadCheckpoint{}
-	err := dcp.load(cpFilePath)
-	if err != nil {
-		os.Remove(cpFilePath)
-	}
-
-	// Get the object detailed meta.
-	meta, err := bucket.GetObjectDetailedMeta(objectKey, payerOptions...)
-	if err != nil {
-		return err
-	}
-
-	// Load error or data invalid. Re-initialize the download.
-	valid, err := dcp.isValid(meta, uRange)
-	if err != nil || !valid {
-		if err = dcp.prepare(meta, &bucket, objectKey, filePath, partSize, uRange); err != nil {
-			return err
-		}
-		os.Remove(cpFilePath)
-	}
-
-	// Create the file if not exists. Otherwise the parts download will overwrite it.
-	fd, err := os.OpenFile(tempFilePath, os.O_WRONLY|os.O_CREATE, FilePermMode)
-	if err != nil {
-		return err
-	}
-	fd.Close()
-
-	// Unfinished parts
-	parts := dcp.todoParts()
-	jobs := make(chan downloadPart, len(parts))
-	results := make(chan downloadPart, len(parts))
-	failed := make(chan error)
-	die := make(chan bool)
-
-	completedBytes := dcp.getCompletedBytes()
-	event := newProgressEvent(TransferStartedEvent, completedBytes, dcp.ObjStat.Size)
-	publishProgress(listener, event)
-
-	// Start the download workers routine
-	arg := downloadWorkerArg{&bucket, objectKey, tempFilePath, options, downloadPartHooker, dcp.enableCRC}
-	for w := 1; w <= routines; w++ {
-		go downloadWorker(w, arg, jobs, results, failed, die)
-	}
-
-	// Concurrently downloads parts
-	go downloadScheduler(jobs, parts)
-
-	// Wait for the parts download finished
-	completed := 0
-	for completed < len(parts) {
-		select {
-		case part := <-results:
-			completed++
-			dcp.PartStat[part.Index] = true
-			dcp.Parts[part.Index].CRC64 = part.CRC64
-			dcp.dump(cpFilePath)
-			completedBytes += (part.End - part.Start + 1)
-			event = newProgressEvent(TransferDataEvent, completedBytes, dcp.ObjStat.Size)
-			publishProgress(listener, event)
-		case err := <-failed:
-			close(die)
-			event = newProgressEvent(TransferFailedEvent, completedBytes, dcp.ObjStat.Size)
-			publishProgress(listener, event)
-			return err
-		}
-
-		if completed >= len(parts) {
-			break
-		}
-	}
-
-	event = newProgressEvent(TransferCompletedEvent, completedBytes, dcp.ObjStat.Size)
-	publishProgress(listener, event)
-
-	if dcp.enableCRC {
-		actualCRC := combineCRCInParts(dcp.Parts)
-		err = checkDownloadCRC(actualCRC, dcp.CRC)
-		if err != nil {
-			return err
-		}
-	}
-
-	return dcp.complete(cpFilePath, tempFilePath)
-}

+ 0 - 94
vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/error.go

@@ -1,94 +0,0 @@
-package oss
-
-import (
-	"encoding/xml"
-	"fmt"
-	"net/http"
-	"strings"
-)
-
-// ServiceError contains fields of the error response from Oss Service REST API.
-type ServiceError struct {
-	XMLName    xml.Name `xml:"Error"`
-	Code       string   `xml:"Code"`      // The error code returned from OSS to the caller
-	Message    string   `xml:"Message"`   // The detail error message from OSS
-	RequestID  string   `xml:"RequestId"` // The UUID used to uniquely identify the request
-	HostID     string   `xml:"HostId"`    // The OSS server cluster's Id
-	Endpoint   string   `xml:"Endpoint"`
-	RawMessage string   // The raw messages from OSS
-	StatusCode int      // HTTP status code
-}
-
-// Error implements interface error
-func (e ServiceError) Error() string {
-	if e.Endpoint == "" {
-		return fmt.Sprintf("oss: service returned error: StatusCode=%d, ErrorCode=%s, ErrorMessage=\"%s\", RequestId=%s",
-			e.StatusCode, e.Code, e.Message, e.RequestID)
-	}
-	return fmt.Sprintf("oss: service returned error: StatusCode=%d, ErrorCode=%s, ErrorMessage=\"%s\", RequestId=%s, Endpoint=%s",
-		e.StatusCode, e.Code, e.Message, e.RequestID, e.Endpoint)
-}
-
-// UnexpectedStatusCodeError is returned when a storage service responds with neither an error
-// nor with an HTTP status code indicating success.
-type UnexpectedStatusCodeError struct {
-	allowed []int // The expected HTTP stats code returned from OSS
-	got     int   // The actual HTTP status code from OSS
-}
-
-// Error implements interface error
-func (e UnexpectedStatusCodeError) Error() string {
-	s := func(i int) string { return fmt.Sprintf("%d %s", i, http.StatusText(i)) }
-
-	got := s(e.got)
-	expected := []string{}
-	for _, v := range e.allowed {
-		expected = append(expected, s(v))
-	}
-	return fmt.Sprintf("oss: status code from service response is %s; was expecting %s",
-		got, strings.Join(expected, " or "))
-}
-
-// Got is the actual status code returned by oss.
-func (e UnexpectedStatusCodeError) Got() int {
-	return e.got
-}
-
-// checkRespCode returns UnexpectedStatusError if the given response code is not
-// one of the allowed status codes; otherwise nil.
-func checkRespCode(respCode int, allowed []int) error {
-	for _, v := range allowed {
-		if respCode == v {
-			return nil
-		}
-	}
-	return UnexpectedStatusCodeError{allowed, respCode}
-}
-
-// CRCCheckError is returned when crc check is inconsistent between client and server
-type CRCCheckError struct {
-	clientCRC uint64 // Calculated CRC64 in client
-	serverCRC uint64 // Calculated CRC64 in server
-	operation string // Upload operations such as PutObject/AppendObject/UploadPart, etc
-	requestID string // The request id of this operation
-}
-
-// Error implements interface error
-func (e CRCCheckError) Error() string {
-	return fmt.Sprintf("oss: the crc of %s is inconsistent, client %d but server %d; request id is %s",
-		e.operation, e.clientCRC, e.serverCRC, e.requestID)
-}
-
-func checkDownloadCRC(clientCRC, serverCRC uint64) error {
-	if clientCRC == serverCRC {
-		return nil
-	}
-	return CRCCheckError{clientCRC, serverCRC, "DownloadFile", ""}
-}
-
-func checkCRC(resp *Response, operation string) error {
-	if resp.Headers.Get(HTTPHeaderOssCRC64) == "" || resp.ClientCRC == resp.ServerCRC {
-		return nil
-	}
-	return CRCCheckError{resp.ClientCRC, resp.ServerCRC, operation, resp.Headers.Get(HTTPHeaderOssRequestID)}
-}

+ 0 - 28
vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/limit_reader_1_6.go

@@ -1,28 +0,0 @@
-// +build !go1.7
-
-// "golang.org/x/time/rate" is depended on golang context package  go1.7 onward
-// this file is only for build,not supports limit upload speed
-package oss
-
-import (
-	"fmt"
-	"io"
-)
-
-const (
-	perTokenBandwidthSize int = 1024
-)
-
-type OssLimiter struct {
-}
-
-type LimitSpeedReader struct {
-	io.ReadCloser
-	reader     io.Reader
-	ossLimiter *OssLimiter
-}
-
-func GetOssLimiter(uploadSpeed int) (ossLimiter *OssLimiter, err error) {
-	err = fmt.Errorf("rate.Limiter is not supported below version go1.7")
-	return nil, err
-}

+ 0 - 91
vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/limit_reader_1_7.go

@@ -1,91 +0,0 @@
-// +build go1.7
-
-package oss
-
-import (
-	"fmt"
-	"io"
-	"math"
-	"time"
-
-	"golang.org/x/time/rate"
-)
-
-const (
-	perTokenBandwidthSize int = 1024
-)
-
-// OssLimiter: wrapper rate.Limiter
-type OssLimiter struct {
-	limiter *rate.Limiter
-}
-
-// GetOssLimiter:create OssLimiter
-// uploadSpeed:KB/s
-func GetOssLimiter(uploadSpeed int) (ossLimiter *OssLimiter, err error) {
-	limiter := rate.NewLimiter(rate.Limit(uploadSpeed), uploadSpeed)
-
-	// first consume the initial full token,the limiter will behave more accurately
-	limiter.AllowN(time.Now(), uploadSpeed)
-
-	return &OssLimiter{
-		limiter: limiter,
-	}, nil
-}
-
-// LimitSpeedReader: for limit bandwidth upload
-type LimitSpeedReader struct {
-	io.ReadCloser
-	reader     io.Reader
-	ossLimiter *OssLimiter
-}
-
-// Read
-func (r *LimitSpeedReader) Read(p []byte) (n int, err error) {
-	n = 0
-	err = nil
-	start := 0
-	burst := r.ossLimiter.limiter.Burst()
-	var end int
-	var tmpN int
-	var tc int
-	for start < len(p) {
-		if start+burst*perTokenBandwidthSize < len(p) {
-			end = start + burst*perTokenBandwidthSize
-		} else {
-			end = len(p)
-		}
-
-		tmpN, err = r.reader.Read(p[start:end])
-		if tmpN > 0 {
-			n += tmpN
-			start = n
-		}
-
-		if err != nil {
-			return
-		}
-
-		tc = int(math.Ceil(float64(tmpN) / float64(perTokenBandwidthSize)))
-		now := time.Now()
-		re := r.ossLimiter.limiter.ReserveN(now, tc)
-		if !re.OK() {
-			err = fmt.Errorf("LimitSpeedReader.Read() failure,ReserveN error,start:%d,end:%d,burst:%d,perTokenBandwidthSize:%d",
-				start, end, burst, perTokenBandwidthSize)
-			return
-		} else {
-			timeDelay := re.Delay()
-			time.Sleep(timeDelay)
-		}
-	}
-	return
-}
-
-// Close ...
-func (r *LimitSpeedReader) Close() error {
-	rc, ok := r.reader.(io.ReadCloser)
-	if ok {
-		return rc.Close()
-	}
-	return nil
-}

+ 0 - 257
vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/livechannel.go

@@ -1,257 +0,0 @@
-package oss
-
-import (
-	"bytes"
-	"encoding/xml"
-	"fmt"
-	"io"
-	"net/http"
-	"strconv"
-	"time"
-)
-
-//
-// CreateLiveChannel    create a live-channel
-//
-// channelName  the name of the channel
-// config       configuration of the channel
-//
-// CreateLiveChannelResult  the result of create live-channel
-// error        nil if success, otherwise error
-//
-func (bucket Bucket) CreateLiveChannel(channelName string, config LiveChannelConfiguration) (CreateLiveChannelResult, error) {
-	var out CreateLiveChannelResult
-
-	bs, err := xml.Marshal(config)
-	if err != nil {
-		return out, err
-	}
-
-	buffer := new(bytes.Buffer)
-	buffer.Write(bs)
-
-	params := map[string]interface{}{}
-	params["live"] = nil
-	resp, err := bucket.do("PUT", channelName, params, nil, buffer, nil)
-	if err != nil {
-		return out, err
-	}
-	defer resp.Body.Close()
-
-	err = xmlUnmarshal(resp.Body, &out)
-	return out, err
-}
-
-//
-// PutLiveChannelStatus Set the status of the live-channel: enabled/disabled
-//
-// channelName  the name of the channel
-// status       enabled/disabled
-//
-// error        nil if success, otherwise error
-//
-func (bucket Bucket) PutLiveChannelStatus(channelName, status string) error {
-	params := map[string]interface{}{}
-	params["live"] = nil
-	params["status"] = status
-
-	resp, err := bucket.do("PUT", channelName, params, nil, nil, nil)
-	if err != nil {
-		return err
-	}
-	defer resp.Body.Close()
-
-	return checkRespCode(resp.StatusCode, []int{http.StatusOK})
-}
-
-// PostVodPlaylist  create an playlist based on the specified playlist name, startTime and endTime
-//
-// channelName  the name of the channel
-// playlistName the name of the playlist, must end with ".m3u8"
-// startTime    the start time of the playlist
-// endTime      the endtime of the playlist
-//
-// error        nil if success, otherwise error
-//
-func (bucket Bucket) PostVodPlaylist(channelName, playlistName string, startTime, endTime time.Time) error {
-	params := map[string]interface{}{}
-	params["vod"] = nil
-	params["startTime"] = strconv.FormatInt(startTime.Unix(), 10)
-	params["endTime"] = strconv.FormatInt(endTime.Unix(), 10)
-
-	key := fmt.Sprintf("%s/%s", channelName, playlistName)
-	resp, err := bucket.do("POST", key, params, nil, nil, nil)
-	if err != nil {
-		return err
-	}
-	defer resp.Body.Close()
-
-	return checkRespCode(resp.StatusCode, []int{http.StatusOK})
-}
-
-// GetVodPlaylist  get the playlist based on the specified channelName, startTime and endTime
-//
-// channelName  the name of the channel
-// startTime    the start time of the playlist
-// endTime      the endtime of the playlist
-//
-// io.ReadCloser reader instance for reading data from response. It must be called close() after the usage and only valid when error is nil.
-// error        nil if success, otherwise error
-//
-func (bucket Bucket) GetVodPlaylist(channelName string, startTime, endTime time.Time) (io.ReadCloser, error) {
-	params := map[string]interface{}{}
-	params["vod"] = nil
-	params["startTime"] = strconv.FormatInt(startTime.Unix(), 10)
-	params["endTime"] = strconv.FormatInt(endTime.Unix(), 10)
-
-	resp, err := bucket.do("GET", channelName, params, nil, nil, nil)
-	if err != nil {
-		return nil, err
-	}
-
-	return resp.Body, nil
-}
-
-//
-// GetLiveChannelStat   Get the state of the live-channel
-//
-// channelName  the name of the channel
-//
-// LiveChannelStat  the state of the live-channel
-// error        nil if success, otherwise error
-//
-func (bucket Bucket) GetLiveChannelStat(channelName string) (LiveChannelStat, error) {
-	var out LiveChannelStat
-	params := map[string]interface{}{}
-	params["live"] = nil
-	params["comp"] = "stat"
-
-	resp, err := bucket.do("GET", channelName, params, nil, nil, nil)
-	if err != nil {
-		return out, err
-	}
-	defer resp.Body.Close()
-
-	err = xmlUnmarshal(resp.Body, &out)
-	return out, err
-}
-
-//
-// GetLiveChannelInfo   Get the configuration info of the live-channel
-//
-// channelName  the name of the channel
-//
-// LiveChannelConfiguration the configuration info of the live-channel
-// error        nil if success, otherwise error
-//
-func (bucket Bucket) GetLiveChannelInfo(channelName string) (LiveChannelConfiguration, error) {
-	var out LiveChannelConfiguration
-	params := map[string]interface{}{}
-	params["live"] = nil
-
-	resp, err := bucket.do("GET", channelName, params, nil, nil, nil)
-	if err != nil {
-		return out, err
-	}
-	defer resp.Body.Close()
-
-	err = xmlUnmarshal(resp.Body, &out)
-	return out, err
-}
-
-//
-// GetLiveChannelHistory    Get push records of live-channel
-//
-// channelName  the name of the channel
-//
-// LiveChannelHistory   push records
-// error        nil if success, otherwise error
-//
-func (bucket Bucket) GetLiveChannelHistory(channelName string) (LiveChannelHistory, error) {
-	var out LiveChannelHistory
-	params := map[string]interface{}{}
-	params["live"] = nil
-	params["comp"] = "history"
-
-	resp, err := bucket.do("GET", channelName, params, nil, nil, nil)
-	if err != nil {
-		return out, err
-	}
-	defer resp.Body.Close()
-
-	err = xmlUnmarshal(resp.Body, &out)
-	return out, err
-}
-
-//
-// ListLiveChannel  list the live-channels
-//
-// options  Prefix: filter by the name start with the value of "Prefix"
-//          MaxKeys: the maximum count returned
-//          Marker: cursor from which starting list
-//
-// ListLiveChannelResult    live-channel list
-// error    nil if success, otherwise error
-//
-func (bucket Bucket) ListLiveChannel(options ...Option) (ListLiveChannelResult, error) {
-	var out ListLiveChannelResult
-
-	params, err := getRawParams(options)
-	if err != nil {
-		return out, err
-	}
-
-	params["live"] = nil
-
-	resp, err := bucket.do("GET", "", params, nil, nil, nil)
-	if err != nil {
-		return out, err
-	}
-	defer resp.Body.Close()
-
-	err = xmlUnmarshal(resp.Body, &out)
-	return out, err
-}
-
-//
-// DeleteLiveChannel    Delete the live-channel. When a client trying to stream the live-channel, the operation will fail. it will only delete the live-channel itself and the object generated by the live-channel will not be deleted.
-//
-// channelName  the name of the channel
-//
-// error        nil if success, otherwise error
-//
-func (bucket Bucket) DeleteLiveChannel(channelName string) error {
-	params := map[string]interface{}{}
-	params["live"] = nil
-
-	if channelName == "" {
-		return fmt.Errorf("invalid argument: channel name is empty")
-	}
-
-	resp, err := bucket.do("DELETE", channelName, params, nil, nil, nil)
-	if err != nil {
-		return err
-	}
-	defer resp.Body.Close()
-
-	return checkRespCode(resp.StatusCode, []int{http.StatusNoContent})
-}
-
-//
-// SignRtmpURL  Generate a RTMP push-stream signature URL for the trusted user to push the RTMP stream to the live-channel.
-//
-// channelName  the name of the channel
-// playlistName the name of the playlist, must end with ".m3u8"
-// expires      expiration (in seconds)
-//
-// string       singed rtmp push stream url
-// error        nil if success, otherwise error
-//
-func (bucket Bucket) SignRtmpURL(channelName, playlistName string, expires int64) (string, error) {
-	if expires <= 0 {
-		return "", fmt.Errorf("invalid argument: %d, expires must greater than 0", expires)
-	}
-	expiration := time.Now().Unix() + expires
-
-	return bucket.Client.Conn.signRtmpURL(bucket.BucketName, channelName, playlistName, expiration), nil
-}

+ 0 - 245
vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/mime.go

@@ -1,245 +0,0 @@
-package oss
-
-import (
-	"mime"
-	"path"
-	"strings"
-)
-
-var extToMimeType = map[string]string{
-	".xlsx":    "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
-	".xltx":    "application/vnd.openxmlformats-officedocument.spreadsheetml.template",
-	".potx":    "application/vnd.openxmlformats-officedocument.presentationml.template",
-	".ppsx":    "application/vnd.openxmlformats-officedocument.presentationml.slideshow",
-	".pptx":    "application/vnd.openxmlformats-officedocument.presentationml.presentation",
-	".sldx":    "application/vnd.openxmlformats-officedocument.presentationml.slide",
-	".docx":    "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
-	".dotx":    "application/vnd.openxmlformats-officedocument.wordprocessingml.template",
-	".xlam":    "application/vnd.ms-excel.addin.macroEnabled.12",
-	".xlsb":    "application/vnd.ms-excel.sheet.binary.macroEnabled.12",
-	".apk":     "application/vnd.android.package-archive",
-	".hqx":     "application/mac-binhex40",
-	".cpt":     "application/mac-compactpro",
-	".doc":     "application/msword",
-	".ogg":     "application/ogg",
-	".pdf":     "application/pdf",
-	".rtf":     "text/rtf",
-	".mif":     "application/vnd.mif",
-	".xls":     "application/vnd.ms-excel",
-	".ppt":     "application/vnd.ms-powerpoint",
-	".odc":     "application/vnd.oasis.opendocument.chart",
-	".odb":     "application/vnd.oasis.opendocument.database",
-	".odf":     "application/vnd.oasis.opendocument.formula",
-	".odg":     "application/vnd.oasis.opendocument.graphics",
-	".otg":     "application/vnd.oasis.opendocument.graphics-template",
-	".odi":     "application/vnd.oasis.opendocument.image",
-	".odp":     "application/vnd.oasis.opendocument.presentation",
-	".otp":     "application/vnd.oasis.opendocument.presentation-template",
-	".ods":     "application/vnd.oasis.opendocument.spreadsheet",
-	".ots":     "application/vnd.oasis.opendocument.spreadsheet-template",
-	".odt":     "application/vnd.oasis.opendocument.text",
-	".odm":     "application/vnd.oasis.opendocument.text-master",
-	".ott":     "application/vnd.oasis.opendocument.text-template",
-	".oth":     "application/vnd.oasis.opendocument.text-web",
-	".sxw":     "application/vnd.sun.xml.writer",
-	".stw":     "application/vnd.sun.xml.writer.template",
-	".sxc":     "application/vnd.sun.xml.calc",
-	".stc":     "application/vnd.sun.xml.calc.template",
-	".sxd":     "application/vnd.sun.xml.draw",
-	".std":     "application/vnd.sun.xml.draw.template",
-	".sxi":     "application/vnd.sun.xml.impress",
-	".sti":     "application/vnd.sun.xml.impress.template",
-	".sxg":     "application/vnd.sun.xml.writer.global",
-	".sxm":     "application/vnd.sun.xml.math",
-	".sis":     "application/vnd.symbian.install",
-	".wbxml":   "application/vnd.wap.wbxml",
-	".wmlc":    "application/vnd.wap.wmlc",
-	".wmlsc":   "application/vnd.wap.wmlscriptc",
-	".bcpio":   "application/x-bcpio",
-	".torrent": "application/x-bittorrent",
-	".bz2":     "application/x-bzip2",
-	".vcd":     "application/x-cdlink",
-	".pgn":     "application/x-chess-pgn",
-	".cpio":    "application/x-cpio",
-	".csh":     "application/x-csh",
-	".dvi":     "application/x-dvi",
-	".spl":     "application/x-futuresplash",
-	".gtar":    "application/x-gtar",
-	".hdf":     "application/x-hdf",
-	".jar":     "application/x-java-archive",
-	".jnlp":    "application/x-java-jnlp-file",
-	".js":      "application/x-javascript",
-	".ksp":     "application/x-kspread",
-	".chrt":    "application/x-kchart",
-	".kil":     "application/x-killustrator",
-	".latex":   "application/x-latex",
-	".rpm":     "application/x-rpm",
-	".sh":      "application/x-sh",
-	".shar":    "application/x-shar",
-	".swf":     "application/x-shockwave-flash",
-	".sit":     "application/x-stuffit",
-	".sv4cpio": "application/x-sv4cpio",
-	".sv4crc":  "application/x-sv4crc",
-	".tar":     "application/x-tar",
-	".tcl":     "application/x-tcl",
-	".tex":     "application/x-tex",
-	".man":     "application/x-troff-man",
-	".me":      "application/x-troff-me",
-	".ms":      "application/x-troff-ms",
-	".ustar":   "application/x-ustar",
-	".src":     "application/x-wais-source",
-	".zip":     "application/zip",
-	".m3u":     "audio/x-mpegurl",
-	".ra":      "audio/x-pn-realaudio",
-	".wav":     "audio/x-wav",
-	".wma":     "audio/x-ms-wma",
-	".wax":     "audio/x-ms-wax",
-	".pdb":     "chemical/x-pdb",
-	".xyz":     "chemical/x-xyz",
-	".bmp":     "image/bmp",
-	".gif":     "image/gif",
-	".ief":     "image/ief",
-	".png":     "image/png",
-	".wbmp":    "image/vnd.wap.wbmp",
-	".ras":     "image/x-cmu-raster",
-	".pnm":     "image/x-portable-anymap",
-	".pbm":     "image/x-portable-bitmap",
-	".pgm":     "image/x-portable-graymap",
-	".ppm":     "image/x-portable-pixmap",
-	".rgb":     "image/x-rgb",
-	".xbm":     "image/x-xbitmap",
-	".xpm":     "image/x-xpixmap",
-	".xwd":     "image/x-xwindowdump",
-	".css":     "text/css",
-	".rtx":     "text/richtext",
-	".tsv":     "text/tab-separated-values",
-	".jad":     "text/vnd.sun.j2me.app-descriptor",
-	".wml":     "text/vnd.wap.wml",
-	".wmls":    "text/vnd.wap.wmlscript",
-	".etx":     "text/x-setext",
-	".mxu":     "video/vnd.mpegurl",
-	".flv":     "video/x-flv",
-	".wm":      "video/x-ms-wm",
-	".wmv":     "video/x-ms-wmv",
-	".wmx":     "video/x-ms-wmx",
-	".wvx":     "video/x-ms-wvx",
-	".avi":     "video/x-msvideo",
-	".movie":   "video/x-sgi-movie",
-	".ice":     "x-conference/x-cooltalk",
-	".3gp":     "video/3gpp",
-	".ai":      "application/postscript",
-	".aif":     "audio/x-aiff",
-	".aifc":    "audio/x-aiff",
-	".aiff":    "audio/x-aiff",
-	".asc":     "text/plain",
-	".atom":    "application/atom+xml",
-	".au":      "audio/basic",
-	".bin":     "application/octet-stream",
-	".cdf":     "application/x-netcdf",
-	".cgm":     "image/cgm",
-	".class":   "application/octet-stream",
-	".dcr":     "application/x-director",
-	".dif":     "video/x-dv",
-	".dir":     "application/x-director",
-	".djv":     "image/vnd.djvu",
-	".djvu":    "image/vnd.djvu",
-	".dll":     "application/octet-stream",
-	".dmg":     "application/octet-stream",
-	".dms":     "application/octet-stream",
-	".dtd":     "application/xml-dtd",
-	".dv":      "video/x-dv",
-	".dxr":     "application/x-director",
-	".eps":     "application/postscript",
-	".exe":     "application/octet-stream",
-	".ez":      "application/andrew-inset",
-	".gram":    "application/srgs",
-	".grxml":   "application/srgs+xml",
-	".gz":      "application/x-gzip",
-	".htm":     "text/html",
-	".html":    "text/html",
-	".ico":     "image/x-icon",
-	".ics":     "text/calendar",
-	".ifb":     "text/calendar",
-	".iges":    "model/iges",
-	".igs":     "model/iges",
-	".jp2":     "image/jp2",
-	".jpe":     "image/jpeg",
-	".jpeg":    "image/jpeg",
-	".jpg":     "image/jpeg",
-	".kar":     "audio/midi",
-	".lha":     "application/octet-stream",
-	".lzh":     "application/octet-stream",
-	".m4a":     "audio/mp4a-latm",
-	".m4p":     "audio/mp4a-latm",
-	".m4u":     "video/vnd.mpegurl",
-	".m4v":     "video/x-m4v",
-	".mac":     "image/x-macpaint",
-	".mathml":  "application/mathml+xml",
-	".mesh":    "model/mesh",
-	".mid":     "audio/midi",
-	".midi":    "audio/midi",
-	".mov":     "video/quicktime",
-	".mp2":     "audio/mpeg",
-	".mp3":     "audio/mpeg",
-	".mp4":     "video/mp4",
-	".mpe":     "video/mpeg",
-	".mpeg":    "video/mpeg",
-	".mpg":     "video/mpeg",
-	".mpga":    "audio/mpeg",
-	".msh":     "model/mesh",
-	".nc":      "application/x-netcdf",
-	".oda":     "application/oda",
-	".ogv":     "video/ogv",
-	".pct":     "image/pict",
-	".pic":     "image/pict",
-	".pict":    "image/pict",
-	".pnt":     "image/x-macpaint",
-	".pntg":    "image/x-macpaint",
-	".ps":      "application/postscript",
-	".qt":      "video/quicktime",
-	".qti":     "image/x-quicktime",
-	".qtif":    "image/x-quicktime",
-	".ram":     "audio/x-pn-realaudio",
-	".rdf":     "application/rdf+xml",
-	".rm":      "application/vnd.rn-realmedia",
-	".roff":    "application/x-troff",
-	".sgm":     "text/sgml",
-	".sgml":    "text/sgml",
-	".silo":    "model/mesh",
-	".skd":     "application/x-koan",
-	".skm":     "application/x-koan",
-	".skp":     "application/x-koan",
-	".skt":     "application/x-koan",
-	".smi":     "application/smil",
-	".smil":    "application/smil",
-	".snd":     "audio/basic",
-	".so":      "application/octet-stream",
-	".svg":     "image/svg+xml",
-	".t":       "application/x-troff",
-	".texi":    "application/x-texinfo",
-	".texinfo": "application/x-texinfo",
-	".tif":     "image/tiff",
-	".tiff":    "image/tiff",
-	".tr":      "application/x-troff",
-	".txt":     "text/plain",
-	".vrml":    "model/vrml",
-	".vxml":    "application/voicexml+xml",
-	".webm":    "video/webm",
-	".wrl":     "model/vrml",
-	".xht":     "application/xhtml+xml",
-	".xhtml":   "application/xhtml+xml",
-	".xml":     "application/xml",
-	".xsl":     "application/xml",
-	".xslt":    "application/xslt+xml",
-	".xul":     "application/vnd.mozilla.xul+xml",
-}
-
-// TypeByExtension returns the MIME type associated with the file extension ext.
-// gets the file's MIME type for HTTP header Content-Type
-func TypeByExtension(filePath string) string {
-	typ := mime.TypeByExtension(path.Ext(filePath))
-	if typ == "" {
-		typ = extToMimeType[strings.ToLower(path.Ext(filePath))]
-	}
-	return typ
-}

+ 0 - 68
vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/model.go

@@ -1,68 +0,0 @@
-package oss
-
-import (
-	"hash"
-	"io"
-	"net/http"
-)
-
-// Response defines HTTP response from OSS
-type Response struct {
-	StatusCode int
-	Headers    http.Header
-	Body       io.ReadCloser
-	ClientCRC  uint64
-	ServerCRC  uint64
-}
-
-func (r *Response) Read(p []byte) (n int, err error) {
-	return r.Body.Read(p)
-}
-
-func (r *Response) Close() error {
-	return r.Body.Close()
-}
-
-// PutObjectRequest is the request of DoPutObject
-type PutObjectRequest struct {
-	ObjectKey string
-	Reader    io.Reader
-}
-
-// GetObjectRequest is the request of DoGetObject
-type GetObjectRequest struct {
-	ObjectKey string
-}
-
-// GetObjectResult is the result of DoGetObject
-type GetObjectResult struct {
-	Response  *Response
-	ClientCRC hash.Hash64
-	ServerCRC uint64
-}
-
-// AppendObjectRequest is the requtest of DoAppendObject
-type AppendObjectRequest struct {
-	ObjectKey string
-	Reader    io.Reader
-	Position  int64
-}
-
-// AppendObjectResult is the result of DoAppendObject
-type AppendObjectResult struct {
-	NextPosition int64
-	CRC          uint64
-}
-
-// UploadPartRequest is the request of DoUploadPart
-type UploadPartRequest struct {
-	InitResult *InitiateMultipartUploadResult
-	Reader     io.Reader
-	PartSize   int64
-	PartNumber int
-}
-
-// UploadPartResult is the result of DoUploadPart
-type UploadPartResult struct {
-	Part UploadPart
-}

+ 0 - 468
vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/multicopy.go

@@ -1,468 +0,0 @@
-package oss
-
-import (
-	"crypto/md5"
-	"encoding/base64"
-	"encoding/json"
-	"errors"
-	"fmt"
-	"io/ioutil"
-	"net/http"
-	"os"
-	"strconv"
-)
-
-// CopyFile is multipart copy object
-//
-// srcBucketName    source bucket name
-// srcObjectKey    source object name
-// destObjectKey    target object name in the form of bucketname.objectkey
-// partSize    the part size in byte.
-// options    object's contraints. Check out function InitiateMultipartUpload.
-//
-// error    it's nil if the operation succeeds, otherwise it's an error object.
-//
-func (bucket Bucket) CopyFile(srcBucketName, srcObjectKey, destObjectKey string, partSize int64, options ...Option) error {
-	destBucketName := bucket.BucketName
-	if partSize < MinPartSize || partSize > MaxPartSize {
-		return errors.New("oss: part size invalid range (1024KB, 5GB]")
-	}
-
-	cpConf := getCpConfig(options)
-	routines := getRoutines(options)
-
-	if cpConf != nil && cpConf.IsEnable {
-		cpFilePath := getCopyCpFilePath(cpConf, srcBucketName, srcObjectKey, destBucketName, destObjectKey)
-		if cpFilePath != "" {
-			return bucket.copyFileWithCp(srcBucketName, srcObjectKey, destBucketName, destObjectKey, partSize, options, cpFilePath, routines)
-		}
-	}
-
-	return bucket.copyFile(srcBucketName, srcObjectKey, destBucketName, destObjectKey,
-		partSize, options, routines)
-}
-
-func getCopyCpFilePath(cpConf *cpConfig, srcBucket, srcObject, destBucket, destObject string) string {
-	if cpConf.FilePath == "" && cpConf.DirPath != "" {
-		dest := fmt.Sprintf("oss://%v/%v", destBucket, destObject)
-		src := fmt.Sprintf("oss://%v/%v", srcBucket, srcObject)
-		cpFileName := getCpFileName(src, dest)
-		cpConf.FilePath = cpConf.DirPath + string(os.PathSeparator) + cpFileName
-	}
-	return cpConf.FilePath
-}
-
-// ----- Concurrently copy without checkpoint ---------
-
-// copyWorkerArg defines the copy worker arguments
-type copyWorkerArg struct {
-	bucket        *Bucket
-	imur          InitiateMultipartUploadResult
-	srcBucketName string
-	srcObjectKey  string
-	options       []Option
-	hook          copyPartHook
-}
-
-// copyPartHook is the hook for testing purpose
-type copyPartHook func(part copyPart) error
-
-var copyPartHooker copyPartHook = defaultCopyPartHook
-
-func defaultCopyPartHook(part copyPart) error {
-	return nil
-}
-
-// copyWorker copies worker
-func copyWorker(id int, arg copyWorkerArg, jobs <-chan copyPart, results chan<- UploadPart, failed chan<- error, die <-chan bool) {
-	for chunk := range jobs {
-		if err := arg.hook(chunk); err != nil {
-			failed <- err
-			break
-		}
-		chunkSize := chunk.End - chunk.Start + 1
-		part, err := arg.bucket.UploadPartCopy(arg.imur, arg.srcBucketName, arg.srcObjectKey,
-			chunk.Start, chunkSize, chunk.Number, arg.options...)
-		if err != nil {
-			failed <- err
-			break
-		}
-		select {
-		case <-die:
-			return
-		default:
-		}
-		results <- part
-	}
-}
-
-// copyScheduler
-func copyScheduler(jobs chan copyPart, parts []copyPart) {
-	for _, part := range parts {
-		jobs <- part
-	}
-	close(jobs)
-}
-
-// copyPart structure
-type copyPart struct {
-	Number int   // Part number (from 1 to 10,000)
-	Start  int64 // The start index in the source file.
-	End    int64 // The end index in the source file
-}
-
-// getCopyParts calculates copy parts
-func getCopyParts(objectSize, partSize int64) []copyPart {
-	parts := []copyPart{}
-	part := copyPart{}
-	i := 0
-	for offset := int64(0); offset < objectSize; offset += partSize {
-		part.Number = i + 1
-		part.Start = offset
-		part.End = GetPartEnd(offset, objectSize, partSize)
-		parts = append(parts, part)
-		i++
-	}
-	return parts
-}
-
-// getSrcObjectBytes gets the source file size
-func getSrcObjectBytes(parts []copyPart) int64 {
-	var ob int64
-	for _, part := range parts {
-		ob += (part.End - part.Start + 1)
-	}
-	return ob
-}
-
-// copyFile is a concurrently copy without checkpoint
-func (bucket Bucket) copyFile(srcBucketName, srcObjectKey, destBucketName, destObjectKey string,
-	partSize int64, options []Option, routines int) error {
-	descBucket, err := bucket.Client.Bucket(destBucketName)
-	srcBucket, err := bucket.Client.Bucket(srcBucketName)
-	listener := getProgressListener(options)
-
-	payerOptions := []Option{}
-	payer := getPayer(options)
-	if payer != "" {
-		payerOptions = append(payerOptions, RequestPayer(PayerType(payer)))
-	}
-
-	meta, err := srcBucket.GetObjectDetailedMeta(srcObjectKey, payerOptions...)
-	if err != nil {
-		return err
-	}
-
-	objectSize, err := strconv.ParseInt(meta.Get(HTTPHeaderContentLength), 10, 0)
-	if err != nil {
-		return err
-	}
-
-	// Get copy parts
-	parts := getCopyParts(objectSize, partSize)
-	// Initialize the multipart upload
-	imur, err := descBucket.InitiateMultipartUpload(destObjectKey, options...)
-	if err != nil {
-		return err
-	}
-
-	jobs := make(chan copyPart, len(parts))
-	results := make(chan UploadPart, len(parts))
-	failed := make(chan error)
-	die := make(chan bool)
-
-	var completedBytes int64
-	totalBytes := getSrcObjectBytes(parts)
-	event := newProgressEvent(TransferStartedEvent, 0, totalBytes)
-	publishProgress(listener, event)
-
-	// Start to copy workers
-	arg := copyWorkerArg{descBucket, imur, srcBucketName, srcObjectKey, payerOptions, copyPartHooker}
-	for w := 1; w <= routines; w++ {
-		go copyWorker(w, arg, jobs, results, failed, die)
-	}
-
-	// Start the scheduler
-	go copyScheduler(jobs, parts)
-
-	// Wait for the parts finished.
-	completed := 0
-	ups := make([]UploadPart, len(parts))
-	for completed < len(parts) {
-		select {
-		case part := <-results:
-			completed++
-			ups[part.PartNumber-1] = part
-			completedBytes += (parts[part.PartNumber-1].End - parts[part.PartNumber-1].Start + 1)
-			event = newProgressEvent(TransferDataEvent, completedBytes, totalBytes)
-			publishProgress(listener, event)
-		case err := <-failed:
-			close(die)
-			descBucket.AbortMultipartUpload(imur, payerOptions...)
-			event = newProgressEvent(TransferFailedEvent, completedBytes, totalBytes)
-			publishProgress(listener, event)
-			return err
-		}
-
-		if completed >= len(parts) {
-			break
-		}
-	}
-
-	event = newProgressEvent(TransferCompletedEvent, completedBytes, totalBytes)
-	publishProgress(listener, event)
-
-	// Complete the multipart upload
-	_, err = descBucket.CompleteMultipartUpload(imur, ups, payerOptions...)
-	if err != nil {
-		bucket.AbortMultipartUpload(imur, payerOptions...)
-		return err
-	}
-	return nil
-}
-
-// ----- Concurrently copy with checkpoint  -----
-
-const copyCpMagic = "84F1F18C-FF1D-403B-A1D8-9DEB5F65910A"
-
-type copyCheckpoint struct {
-	Magic          string       // Magic
-	MD5            string       // CP content MD5
-	SrcBucketName  string       // Source bucket
-	SrcObjectKey   string       // Source object
-	DestBucketName string       // Target bucket
-	DestObjectKey  string       // Target object
-	CopyID         string       // Copy ID
-	ObjStat        objectStat   // Object stat
-	Parts          []copyPart   // Copy parts
-	CopyParts      []UploadPart // The uploaded parts
-	PartStat       []bool       // The part status
-}
-
-// isValid checks if the data is valid which means CP is valid and object is not updated.
-func (cp copyCheckpoint) isValid(meta http.Header) (bool, error) {
-	// Compare CP's magic number and the MD5.
-	cpb := cp
-	cpb.MD5 = ""
-	js, _ := json.Marshal(cpb)
-	sum := md5.Sum(js)
-	b64 := base64.StdEncoding.EncodeToString(sum[:])
-
-	if cp.Magic != downloadCpMagic || b64 != cp.MD5 {
-		return false, nil
-	}
-
-	objectSize, err := strconv.ParseInt(meta.Get(HTTPHeaderContentLength), 10, 0)
-	if err != nil {
-		return false, err
-	}
-
-	// Compare the object size and last modified time and etag.
-	if cp.ObjStat.Size != objectSize ||
-		cp.ObjStat.LastModified != meta.Get(HTTPHeaderLastModified) ||
-		cp.ObjStat.Etag != meta.Get(HTTPHeaderEtag) {
-		return false, nil
-	}
-
-	return true, nil
-}
-
-// load loads from the checkpoint file
-func (cp *copyCheckpoint) load(filePath string) error {
-	contents, err := ioutil.ReadFile(filePath)
-	if err != nil {
-		return err
-	}
-
-	err = json.Unmarshal(contents, cp)
-	return err
-}
-
-// update updates the parts status
-func (cp *copyCheckpoint) update(part UploadPart) {
-	cp.CopyParts[part.PartNumber-1] = part
-	cp.PartStat[part.PartNumber-1] = true
-}
-
-// dump dumps the CP to the file
-func (cp *copyCheckpoint) dump(filePath string) error {
-	bcp := *cp
-
-	// Calculate MD5
-	bcp.MD5 = ""
-	js, err := json.Marshal(bcp)
-	if err != nil {
-		return err
-	}
-	sum := md5.Sum(js)
-	b64 := base64.StdEncoding.EncodeToString(sum[:])
-	bcp.MD5 = b64
-
-	// Serialization
-	js, err = json.Marshal(bcp)
-	if err != nil {
-		return err
-	}
-
-	// Dump
-	return ioutil.WriteFile(filePath, js, FilePermMode)
-}
-
-// todoParts returns unfinished parts
-func (cp copyCheckpoint) todoParts() []copyPart {
-	dps := []copyPart{}
-	for i, ps := range cp.PartStat {
-		if !ps {
-			dps = append(dps, cp.Parts[i])
-		}
-	}
-	return dps
-}
-
-// getCompletedBytes returns finished bytes count
-func (cp copyCheckpoint) getCompletedBytes() int64 {
-	var completedBytes int64
-	for i, part := range cp.Parts {
-		if cp.PartStat[i] {
-			completedBytes += (part.End - part.Start + 1)
-		}
-	}
-	return completedBytes
-}
-
-// prepare initializes the multipart upload
-func (cp *copyCheckpoint) prepare(meta http.Header, srcBucket *Bucket, srcObjectKey string, destBucket *Bucket, destObjectKey string,
-	partSize int64, options []Option) error {
-	// CP
-	cp.Magic = copyCpMagic
-	cp.SrcBucketName = srcBucket.BucketName
-	cp.SrcObjectKey = srcObjectKey
-	cp.DestBucketName = destBucket.BucketName
-	cp.DestObjectKey = destObjectKey
-
-	objectSize, err := strconv.ParseInt(meta.Get(HTTPHeaderContentLength), 10, 0)
-	if err != nil {
-		return err
-	}
-
-	cp.ObjStat.Size = objectSize
-	cp.ObjStat.LastModified = meta.Get(HTTPHeaderLastModified)
-	cp.ObjStat.Etag = meta.Get(HTTPHeaderEtag)
-
-	// Parts
-	cp.Parts = getCopyParts(objectSize, partSize)
-	cp.PartStat = make([]bool, len(cp.Parts))
-	for i := range cp.PartStat {
-		cp.PartStat[i] = false
-	}
-	cp.CopyParts = make([]UploadPart, len(cp.Parts))
-
-	// Init copy
-	imur, err := destBucket.InitiateMultipartUpload(destObjectKey, options...)
-	if err != nil {
-		return err
-	}
-	cp.CopyID = imur.UploadID
-
-	return nil
-}
-
-func (cp *copyCheckpoint) complete(bucket *Bucket, parts []UploadPart, cpFilePath string, options []Option) error {
-	imur := InitiateMultipartUploadResult{Bucket: cp.DestBucketName,
-		Key: cp.DestObjectKey, UploadID: cp.CopyID}
-	_, err := bucket.CompleteMultipartUpload(imur, parts, options...)
-	if err != nil {
-		return err
-	}
-	os.Remove(cpFilePath)
-	return err
-}
-
-// copyFileWithCp is concurrently copy with checkpoint
-func (bucket Bucket) copyFileWithCp(srcBucketName, srcObjectKey, destBucketName, destObjectKey string,
-	partSize int64, options []Option, cpFilePath string, routines int) error {
-	descBucket, err := bucket.Client.Bucket(destBucketName)
-	srcBucket, err := bucket.Client.Bucket(srcBucketName)
-	listener := getProgressListener(options)
-
-	payerOptions := []Option{}
-	payer := getPayer(options)
-	if payer != "" {
-		payerOptions = append(payerOptions, RequestPayer(PayerType(payer)))
-	}
-
-	// Load CP data
-	ccp := copyCheckpoint{}
-	err = ccp.load(cpFilePath)
-	if err != nil {
-		os.Remove(cpFilePath)
-	}
-
-	// Make sure the object is not updated.
-	meta, err := srcBucket.GetObjectDetailedMeta(srcObjectKey, payerOptions...)
-	if err != nil {
-		return err
-	}
-
-	// Load error or the CP data is invalid---reinitialize
-	valid, err := ccp.isValid(meta)
-	if err != nil || !valid {
-		if err = ccp.prepare(meta, srcBucket, srcObjectKey, descBucket, destObjectKey, partSize, options); err != nil {
-			return err
-		}
-		os.Remove(cpFilePath)
-	}
-
-	// Unfinished parts
-	parts := ccp.todoParts()
-	imur := InitiateMultipartUploadResult{
-		Bucket:   destBucketName,
-		Key:      destObjectKey,
-		UploadID: ccp.CopyID}
-
-	jobs := make(chan copyPart, len(parts))
-	results := make(chan UploadPart, len(parts))
-	failed := make(chan error)
-	die := make(chan bool)
-
-	completedBytes := ccp.getCompletedBytes()
-	event := newProgressEvent(TransferStartedEvent, completedBytes, ccp.ObjStat.Size)
-	publishProgress(listener, event)
-
-	// Start the worker coroutines
-	arg := copyWorkerArg{descBucket, imur, srcBucketName, srcObjectKey, payerOptions, copyPartHooker}
-	for w := 1; w <= routines; w++ {
-		go copyWorker(w, arg, jobs, results, failed, die)
-	}
-
-	// Start the scheduler
-	go copyScheduler(jobs, parts)
-
-	// Wait for the parts completed.
-	completed := 0
-	for completed < len(parts) {
-		select {
-		case part := <-results:
-			completed++
-			ccp.update(part)
-			ccp.dump(cpFilePath)
-			completedBytes += (parts[part.PartNumber-1].End - parts[part.PartNumber-1].Start + 1)
-			event = newProgressEvent(TransferDataEvent, completedBytes, ccp.ObjStat.Size)
-			publishProgress(listener, event)
-		case err := <-failed:
-			close(die)
-			event = newProgressEvent(TransferFailedEvent, completedBytes, ccp.ObjStat.Size)
-			publishProgress(listener, event)
-			return err
-		}
-
-		if completed >= len(parts) {
-			break
-		}
-	}
-
-	event = newProgressEvent(TransferCompletedEvent, completedBytes, ccp.ObjStat.Size)
-	publishProgress(listener, event)
-
-	return ccp.complete(descBucket, ccp.CopyParts, cpFilePath, payerOptions)
-}

+ 0 - 290
vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/multipart.go

@@ -1,290 +0,0 @@
-package oss
-
-import (
-	"bytes"
-	"encoding/xml"
-	"io"
-	"net/http"
-	"net/url"
-	"os"
-	"sort"
-	"strconv"
-)
-
-// InitiateMultipartUpload initializes multipart upload
-//
-// objectKey    object name
-// options    the object constricts for upload. The valid options are CacheControl, ContentDisposition, ContentEncoding, Expires,
-//            ServerSideEncryption, Meta, check out the following link:
-//            https://help.aliyun.com/document_detail/oss/api-reference/multipart-upload/InitiateMultipartUpload.html
-//
-// InitiateMultipartUploadResult    the return value of the InitiateMultipartUpload, which is used for calls later on such as UploadPartFromFile,UploadPartCopy.
-// error    it's nil if the operation succeeds, otherwise it's an error object.
-//
-func (bucket Bucket) InitiateMultipartUpload(objectKey string, options ...Option) (InitiateMultipartUploadResult, error) {
-	var imur InitiateMultipartUploadResult
-	opts := addContentType(options, objectKey)
-	params := map[string]interface{}{}
-	params["uploads"] = nil
-	resp, err := bucket.do("POST", objectKey, params, opts, nil, nil)
-	if err != nil {
-		return imur, err
-	}
-	defer resp.Body.Close()
-
-	err = xmlUnmarshal(resp.Body, &imur)
-	return imur, err
-}
-
-// UploadPart uploads parts
-//
-// After initializing a Multipart Upload, the upload Id and object key could be used for uploading the parts.
-// Each part has its part number (ranges from 1 to 10,000). And for each upload Id, the part number identifies the position of the part in the whole file.
-// And thus with the same part number and upload Id, another part upload will overwrite the data.
-// Except the last one, minimal part size is 100KB. There's no limit on the last part size.
-//
-// imur    the returned value of InitiateMultipartUpload.
-// reader    io.Reader the reader for the part's data.
-// size    the part size.
-// partNumber    the part number (ranges from 1 to 10,000). Invalid part number will lead to InvalidArgument error.
-//
-// UploadPart    the return value of the upload part. It consists of PartNumber and ETag. It's valid when error is nil.
-// error    it's nil if the operation succeeds, otherwise it's an error object.
-//
-func (bucket Bucket) UploadPart(imur InitiateMultipartUploadResult, reader io.Reader,
-	partSize int64, partNumber int, options ...Option) (UploadPart, error) {
-	request := &UploadPartRequest{
-		InitResult: &imur,
-		Reader:     reader,
-		PartSize:   partSize,
-		PartNumber: partNumber,
-	}
-
-	result, err := bucket.DoUploadPart(request, options)
-
-	return result.Part, err
-}
-
-// UploadPartFromFile uploads part from the file.
-//
-// imur    the return value of a successful InitiateMultipartUpload.
-// filePath    the local file path to upload.
-// startPosition    the start position in the local file.
-// partSize    the part size.
-// partNumber    the part number (from 1 to 10,000)
-//
-// UploadPart    the return value consists of PartNumber and ETag.
-// error    it's nil if the operation succeeds, otherwise it's an error object.
-//
-func (bucket Bucket) UploadPartFromFile(imur InitiateMultipartUploadResult, filePath string,
-	startPosition, partSize int64, partNumber int, options ...Option) (UploadPart, error) {
-	var part = UploadPart{}
-	fd, err := os.Open(filePath)
-	if err != nil {
-		return part, err
-	}
-	defer fd.Close()
-	fd.Seek(startPosition, os.SEEK_SET)
-
-	request := &UploadPartRequest{
-		InitResult: &imur,
-		Reader:     fd,
-		PartSize:   partSize,
-		PartNumber: partNumber,
-	}
-
-	result, err := bucket.DoUploadPart(request, options)
-
-	return result.Part, err
-}
-
-// DoUploadPart does the actual part upload.
-//
-// request    part upload request
-//
-// UploadPartResult    the result of uploading part.
-// error    it's nil if the operation succeeds, otherwise it's an error object.
-//
-func (bucket Bucket) DoUploadPart(request *UploadPartRequest, options []Option) (*UploadPartResult, error) {
-	listener := getProgressListener(options)
-	options = append(options, ContentLength(request.PartSize))
-	params := map[string]interface{}{}
-	params["partNumber"] = strconv.Itoa(request.PartNumber)
-	params["uploadId"] = request.InitResult.UploadID
-	resp, err := bucket.do("PUT", request.InitResult.Key, params, options,
-		&io.LimitedReader{R: request.Reader, N: request.PartSize}, listener)
-	if err != nil {
-		return &UploadPartResult{}, err
-	}
-	defer resp.Body.Close()
-
-	part := UploadPart{
-		ETag:       resp.Headers.Get(HTTPHeaderEtag),
-		PartNumber: request.PartNumber,
-	}
-
-	if bucket.getConfig().IsEnableCRC {
-		err = checkCRC(resp, "DoUploadPart")
-		if err != nil {
-			return &UploadPartResult{part}, err
-		}
-	}
-
-	return &UploadPartResult{part}, nil
-}
-
-// UploadPartCopy uploads part copy
-//
-// imur    the return value of InitiateMultipartUpload
-// copySrc    source Object name
-// startPosition    the part's start index in the source file
-// partSize    the part size
-// partNumber    the part number, ranges from 1 to 10,000. If it exceeds the range OSS returns InvalidArgument error.
-// options    the constraints of source object for the copy. The copy happens only when these contraints are met. Otherwise it returns error.
-//            CopySourceIfNoneMatch, CopySourceIfModifiedSince  CopySourceIfUnmodifiedSince, check out the following link for the detail
-//            https://help.aliyun.com/document_detail/oss/api-reference/multipart-upload/UploadPartCopy.html
-//
-// UploadPart    the return value consists of PartNumber and ETag.
-// error    it's nil if the operation succeeds, otherwise it's an error object.
-//
-func (bucket Bucket) UploadPartCopy(imur InitiateMultipartUploadResult, srcBucketName, srcObjectKey string,
-	startPosition, partSize int64, partNumber int, options ...Option) (UploadPart, error) {
-	var out UploadPartCopyResult
-	var part UploadPart
-
-	opts := []Option{CopySource(srcBucketName, url.QueryEscape(srcObjectKey)),
-		CopySourceRange(startPosition, partSize)}
-	opts = append(opts, options...)
-	params := map[string]interface{}{}
-	params["partNumber"] = strconv.Itoa(partNumber)
-	params["uploadId"] = imur.UploadID
-	resp, err := bucket.do("PUT", imur.Key, params, opts, nil, nil)
-	if err != nil {
-		return part, err
-	}
-	defer resp.Body.Close()
-
-	err = xmlUnmarshal(resp.Body, &out)
-	if err != nil {
-		return part, err
-	}
-	part.ETag = out.ETag
-	part.PartNumber = partNumber
-
-	return part, nil
-}
-
-// CompleteMultipartUpload completes the multipart upload.
-//
-// imur    the return value of InitiateMultipartUpload.
-// parts    the array of return value of UploadPart/UploadPartFromFile/UploadPartCopy.
-//
-// CompleteMultipartUploadResponse    the return value when the call succeeds. Only valid when the error is nil.
-// error    it's nil if the operation succeeds, otherwise it's an error object.
-//
-func (bucket Bucket) CompleteMultipartUpload(imur InitiateMultipartUploadResult,
-	parts []UploadPart, options ...Option) (CompleteMultipartUploadResult, error) {
-	var out CompleteMultipartUploadResult
-
-	sort.Sort(uploadParts(parts))
-	cxml := completeMultipartUploadXML{}
-	cxml.Part = parts
-	bs, err := xml.Marshal(cxml)
-	if err != nil {
-		return out, err
-	}
-	buffer := new(bytes.Buffer)
-	buffer.Write(bs)
-
-	params := map[string]interface{}{}
-	params["uploadId"] = imur.UploadID
-	resp, err := bucket.do("POST", imur.Key, params, options, buffer, nil)
-	if err != nil {
-		return out, err
-	}
-	defer resp.Body.Close()
-
-	err = xmlUnmarshal(resp.Body, &out)
-	return out, err
-}
-
-// AbortMultipartUpload aborts the multipart upload.
-//
-// imur    the return value of InitiateMultipartUpload.
-//
-// error    it's nil if the operation succeeds, otherwise it's an error object.
-//
-func (bucket Bucket) AbortMultipartUpload(imur InitiateMultipartUploadResult, options ...Option) error {
-	params := map[string]interface{}{}
-	params["uploadId"] = imur.UploadID
-	resp, err := bucket.do("DELETE", imur.Key, params, options, nil, nil)
-	if err != nil {
-		return err
-	}
-	defer resp.Body.Close()
-	return checkRespCode(resp.StatusCode, []int{http.StatusNoContent})
-}
-
-// ListUploadedParts lists the uploaded parts.
-//
-// imur    the return value of InitiateMultipartUpload.
-//
-// ListUploadedPartsResponse    the return value if it succeeds, only valid when error is nil.
-// error    it's nil if the operation succeeds, otherwise it's an error object.
-//
-func (bucket Bucket) ListUploadedParts(imur InitiateMultipartUploadResult, options ...Option) (ListUploadedPartsResult, error) {
-	var out ListUploadedPartsResult
-	options = append(options, EncodingType("url"))
-
-	params := map[string]interface{}{}
-	params, err := getRawParams(options)
-	if err != nil {
-		return out, err
-	}
-
-	params["uploadId"] = imur.UploadID
-	resp, err := bucket.do("GET", imur.Key, params, nil, nil, nil)
-	if err != nil {
-		return out, err
-	}
-	defer resp.Body.Close()
-
-	err = xmlUnmarshal(resp.Body, &out)
-	if err != nil {
-		return out, err
-	}
-	err = decodeListUploadedPartsResult(&out)
-	return out, err
-}
-
-// ListMultipartUploads lists all ongoing multipart upload tasks
-//
-// options    listObject's filter. Prefix specifies the returned object's prefix; KeyMarker specifies the returned object's start point in lexicographic order;
-//            MaxKeys specifies the max entries to return; Delimiter is the character for grouping object keys.
-//
-// ListMultipartUploadResponse    the return value if it succeeds, only valid when error is nil.
-// error    it's nil if the operation succeeds, otherwise it's an error object.
-//
-func (bucket Bucket) ListMultipartUploads(options ...Option) (ListMultipartUploadResult, error) {
-	var out ListMultipartUploadResult
-
-	options = append(options, EncodingType("url"))
-	params, err := getRawParams(options)
-	if err != nil {
-		return out, err
-	}
-	params["uploads"] = nil
-
-	resp, err := bucket.do("GET", "", params, options, nil, nil)
-	if err != nil {
-		return out, err
-	}
-	defer resp.Body.Close()
-
-	err = xmlUnmarshal(resp.Body, &out)
-	if err != nil {
-		return out, err
-	}
-	err = decodeListMultipartUploadResult(&out)
-	return out, err
-}

+ 0 - 433
vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/option.go

@@ -1,433 +0,0 @@
-package oss
-
-import (
-	"fmt"
-	"net/http"
-	"strconv"
-	"strings"
-	"time"
-)
-
-type optionType string
-
-const (
-	optionParam optionType = "HTTPParameter" // URL parameter
-	optionHTTP  optionType = "HTTPHeader"    // HTTP header
-	optionArg   optionType = "FuncArgument"  // Function argument
-)
-
-const (
-	deleteObjectsQuiet = "delete-objects-quiet"
-	routineNum         = "x-routine-num"
-	checkpointConfig   = "x-cp-config"
-	initCRC64          = "init-crc64"
-	progressListener   = "x-progress-listener"
-	storageClass       = "storage-class"
-)
-
-type (
-	optionValue struct {
-		Value interface{}
-		Type  optionType
-	}
-
-	// Option HTTP option
-	Option func(map[string]optionValue) error
-)
-
-// ACL is an option to set X-Oss-Acl header
-func ACL(acl ACLType) Option {
-	return setHeader(HTTPHeaderOssACL, string(acl))
-}
-
-// ContentType is an option to set Content-Type header
-func ContentType(value string) Option {
-	return setHeader(HTTPHeaderContentType, value)
-}
-
-// ContentLength is an option to set Content-Length header
-func ContentLength(length int64) Option {
-	return setHeader(HTTPHeaderContentLength, strconv.FormatInt(length, 10))
-}
-
-// CacheControl is an option to set Cache-Control header
-func CacheControl(value string) Option {
-	return setHeader(HTTPHeaderCacheControl, value)
-}
-
-// ContentDisposition is an option to set Content-Disposition header
-func ContentDisposition(value string) Option {
-	return setHeader(HTTPHeaderContentDisposition, value)
-}
-
-// ContentEncoding is an option to set Content-Encoding header
-func ContentEncoding(value string) Option {
-	return setHeader(HTTPHeaderContentEncoding, value)
-}
-
-// ContentLanguage is an option to set Content-Language header
-func ContentLanguage(value string) Option {
-	return setHeader(HTTPHeaderContentLanguage, value)
-}
-
-// ContentMD5 is an option to set Content-MD5 header
-func ContentMD5(value string) Option {
-	return setHeader(HTTPHeaderContentMD5, value)
-}
-
-// Expires is an option to set Expires header
-func Expires(t time.Time) Option {
-	return setHeader(HTTPHeaderExpires, t.Format(http.TimeFormat))
-}
-
-// Meta is an option to set Meta header
-func Meta(key, value string) Option {
-	return setHeader(HTTPHeaderOssMetaPrefix+key, value)
-}
-
-// Range is an option to set Range header, [start, end]
-func Range(start, end int64) Option {
-	return setHeader(HTTPHeaderRange, fmt.Sprintf("bytes=%d-%d", start, end))
-}
-
-// NormalizedRange is an option to set Range header, such as 1024-2048 or 1024- or -2048
-func NormalizedRange(nr string) Option {
-	return setHeader(HTTPHeaderRange, fmt.Sprintf("bytes=%s", strings.TrimSpace(nr)))
-}
-
-// AcceptEncoding is an option to set Accept-Encoding header
-func AcceptEncoding(value string) Option {
-	return setHeader(HTTPHeaderAcceptEncoding, value)
-}
-
-// IfModifiedSince is an option to set If-Modified-Since header
-func IfModifiedSince(t time.Time) Option {
-	return setHeader(HTTPHeaderIfModifiedSince, t.Format(http.TimeFormat))
-}
-
-// IfUnmodifiedSince is an option to set If-Unmodified-Since header
-func IfUnmodifiedSince(t time.Time) Option {
-	return setHeader(HTTPHeaderIfUnmodifiedSince, t.Format(http.TimeFormat))
-}
-
-// IfMatch is an option to set If-Match header
-func IfMatch(value string) Option {
-	return setHeader(HTTPHeaderIfMatch, value)
-}
-
-// IfNoneMatch is an option to set IfNoneMatch header
-func IfNoneMatch(value string) Option {
-	return setHeader(HTTPHeaderIfNoneMatch, value)
-}
-
-// CopySource is an option to set X-Oss-Copy-Source header
-func CopySource(sourceBucket, sourceObject string) Option {
-	return setHeader(HTTPHeaderOssCopySource, "/"+sourceBucket+"/"+sourceObject)
-}
-
-// CopySourceRange is an option to set X-Oss-Copy-Source header
-func CopySourceRange(startPosition, partSize int64) Option {
-	val := "bytes=" + strconv.FormatInt(startPosition, 10) + "-" +
-		strconv.FormatInt((startPosition+partSize-1), 10)
-	return setHeader(HTTPHeaderOssCopySourceRange, val)
-}
-
-// CopySourceIfMatch is an option to set X-Oss-Copy-Source-If-Match header
-func CopySourceIfMatch(value string) Option {
-	return setHeader(HTTPHeaderOssCopySourceIfMatch, value)
-}
-
-// CopySourceIfNoneMatch is an option to set X-Oss-Copy-Source-If-None-Match header
-func CopySourceIfNoneMatch(value string) Option {
-	return setHeader(HTTPHeaderOssCopySourceIfNoneMatch, value)
-}
-
-// CopySourceIfModifiedSince is an option to set X-Oss-CopySource-If-Modified-Since header
-func CopySourceIfModifiedSince(t time.Time) Option {
-	return setHeader(HTTPHeaderOssCopySourceIfModifiedSince, t.Format(http.TimeFormat))
-}
-
-// CopySourceIfUnmodifiedSince is an option to set X-Oss-Copy-Source-If-Unmodified-Since header
-func CopySourceIfUnmodifiedSince(t time.Time) Option {
-	return setHeader(HTTPHeaderOssCopySourceIfUnmodifiedSince, t.Format(http.TimeFormat))
-}
-
-// MetadataDirective is an option to set X-Oss-Metadata-Directive header
-func MetadataDirective(directive MetadataDirectiveType) Option {
-	return setHeader(HTTPHeaderOssMetadataDirective, string(directive))
-}
-
-// ServerSideEncryption is an option to set X-Oss-Server-Side-Encryption header
-func ServerSideEncryption(value string) Option {
-	return setHeader(HTTPHeaderOssServerSideEncryption, value)
-}
-
-// ServerSideEncryptionKeyID is an option to set X-Oss-Server-Side-Encryption-Key-Id header
-func ServerSideEncryptionKeyID(value string) Option {
-	return setHeader(HTTPHeaderOssServerSideEncryptionKeyID, value)
-}
-
-// ObjectACL is an option to set X-Oss-Object-Acl header
-func ObjectACL(acl ACLType) Option {
-	return setHeader(HTTPHeaderOssObjectACL, string(acl))
-}
-
-// symlinkTarget is an option to set X-Oss-Symlink-Target
-func symlinkTarget(targetObjectKey string) Option {
-	return setHeader(HTTPHeaderOssSymlinkTarget, targetObjectKey)
-}
-
-// Origin is an option to set Origin header
-func Origin(value string) Option {
-	return setHeader(HTTPHeaderOrigin, value)
-}
-
-// ObjectStorageClass is an option to set the storage class of object
-func ObjectStorageClass(storageClass StorageClassType) Option {
-	return setHeader(HTTPHeaderOssStorageClass, string(storageClass))
-}
-
-// Callback is an option to set callback values
-func Callback(callback string) Option {
-	return setHeader(HTTPHeaderOssCallback, callback)
-}
-
-// CallbackVar is an option to set callback user defined values
-func CallbackVar(callbackVar string) Option {
-	return setHeader(HTTPHeaderOssCallbackVar, callbackVar)
-}
-
-// RequestPayer is an option to set payer who pay for the request
-func RequestPayer(payerType PayerType) Option {
-	return setHeader(HTTPHeaderOSSRequester, string(payerType))
-}
-
-// Delimiter is an option to set delimiler parameter
-func Delimiter(value string) Option {
-	return addParam("delimiter", value)
-}
-
-// Marker is an option to set marker parameter
-func Marker(value string) Option {
-	return addParam("marker", value)
-}
-
-// MaxKeys is an option to set maxkeys parameter
-func MaxKeys(value int) Option {
-	return addParam("max-keys", strconv.Itoa(value))
-}
-
-// Prefix is an option to set prefix parameter
-func Prefix(value string) Option {
-	return addParam("prefix", value)
-}
-
-// EncodingType is an option to set encoding-type parameter
-func EncodingType(value string) Option {
-	return addParam("encoding-type", value)
-}
-
-// MaxUploads is an option to set max-uploads parameter
-func MaxUploads(value int) Option {
-	return addParam("max-uploads", strconv.Itoa(value))
-}
-
-// KeyMarker is an option to set key-marker parameter
-func KeyMarker(value string) Option {
-	return addParam("key-marker", value)
-}
-
-// UploadIDMarker is an option to set upload-id-marker parameter
-func UploadIDMarker(value string) Option {
-	return addParam("upload-id-marker", value)
-}
-
-// MaxParts is an option to set max-parts parameter
-func MaxParts(value int) Option {
-	return addParam("max-parts", strconv.Itoa(value))
-}
-
-// PartNumberMarker is an option to set part-number-marker parameter
-func PartNumberMarker(value int) Option {
-	return addParam("part-number-marker", strconv.Itoa(value))
-}
-
-// DeleteObjectsQuiet false:DeleteObjects in verbose mode; true:DeleteObjects in quite mode. Default is false.
-func DeleteObjectsQuiet(isQuiet bool) Option {
-	return addArg(deleteObjectsQuiet, isQuiet)
-}
-
-// StorageClass bucket storage class
-func StorageClass(value StorageClassType) Option {
-	return addArg(storageClass, value)
-}
-
-// Checkpoint configuration
-type cpConfig struct {
-	IsEnable bool
-	FilePath string
-	DirPath  string
-}
-
-// Checkpoint sets the isEnable flag and checkpoint file path for DownloadFile/UploadFile.
-func Checkpoint(isEnable bool, filePath string) Option {
-	return addArg(checkpointConfig, &cpConfig{IsEnable: isEnable, FilePath: filePath})
-}
-
-// CheckpointDir sets the isEnable flag and checkpoint dir path for DownloadFile/UploadFile.
-func CheckpointDir(isEnable bool, dirPath string) Option {
-	return addArg(checkpointConfig, &cpConfig{IsEnable: isEnable, DirPath: dirPath})
-}
-
-// Routines DownloadFile/UploadFile routine count
-func Routines(n int) Option {
-	return addArg(routineNum, n)
-}
-
-// InitCRC Init AppendObject CRC
-func InitCRC(initCRC uint64) Option {
-	return addArg(initCRC64, initCRC)
-}
-
-// Progress set progress listener
-func Progress(listener ProgressListener) Option {
-	return addArg(progressListener, listener)
-}
-
-// ResponseContentType is an option to set response-content-type param
-func ResponseContentType(value string) Option {
-	return addParam("response-content-type", value)
-}
-
-// ResponseContentLanguage is an option to set response-content-language param
-func ResponseContentLanguage(value string) Option {
-	return addParam("response-content-language", value)
-}
-
-// ResponseExpires is an option to set response-expires param
-func ResponseExpires(value string) Option {
-	return addParam("response-expires", value)
-}
-
-// ResponseCacheControl is an option to set response-cache-control param
-func ResponseCacheControl(value string) Option {
-	return addParam("response-cache-control", value)
-}
-
-// ResponseContentDisposition is an option to set response-content-disposition param
-func ResponseContentDisposition(value string) Option {
-	return addParam("response-content-disposition", value)
-}
-
-// ResponseContentEncoding is an option to set response-content-encoding param
-func ResponseContentEncoding(value string) Option {
-	return addParam("response-content-encoding", value)
-}
-
-// Process is an option to set x-oss-process param
-func Process(value string) Option {
-	return addParam("x-oss-process", value)
-}
-
-func setHeader(key string, value interface{}) Option {
-	return func(params map[string]optionValue) error {
-		if value == nil {
-			return nil
-		}
-		params[key] = optionValue{value, optionHTTP}
-		return nil
-	}
-}
-
-func addParam(key string, value interface{}) Option {
-	return func(params map[string]optionValue) error {
-		if value == nil {
-			return nil
-		}
-		params[key] = optionValue{value, optionParam}
-		return nil
-	}
-}
-
-func addArg(key string, value interface{}) Option {
-	return func(params map[string]optionValue) error {
-		if value == nil {
-			return nil
-		}
-		params[key] = optionValue{value, optionArg}
-		return nil
-	}
-}
-
-func handleOptions(headers map[string]string, options []Option) error {
-	params := map[string]optionValue{}
-	for _, option := range options {
-		if option != nil {
-			if err := option(params); err != nil {
-				return err
-			}
-		}
-	}
-
-	for k, v := range params {
-		if v.Type == optionHTTP {
-			headers[k] = v.Value.(string)
-		}
-	}
-	return nil
-}
-
-func getRawParams(options []Option) (map[string]interface{}, error) {
-	// Option
-	params := map[string]optionValue{}
-	for _, option := range options {
-		if option != nil {
-			if err := option(params); err != nil {
-				return nil, err
-			}
-		}
-	}
-
-	paramsm := map[string]interface{}{}
-	// Serialize
-	for k, v := range params {
-		if v.Type == optionParam {
-			vs := params[k]
-			paramsm[k] = vs.Value.(string)
-		}
-	}
-
-	return paramsm, nil
-}
-
-func findOption(options []Option, param string, defaultVal interface{}) (interface{}, error) {
-	params := map[string]optionValue{}
-	for _, option := range options {
-		if option != nil {
-			if err := option(params); err != nil {
-				return nil, err
-			}
-		}
-	}
-
-	if val, ok := params[param]; ok {
-		return val.Value, nil
-	}
-	return defaultVal, nil
-}
-
-func isOptionSet(options []Option, option string) (bool, interface{}, error) {
-	params := map[string]optionValue{}
-	for _, option := range options {
-		if option != nil {
-			if err := option(params); err != nil {
-				return false, nil, err
-			}
-		}
-	}
-
-	if val, ok := params[option]; ok {
-		return true, val.Value, nil
-	}
-	return false, nil, nil
-}

+ 0 - 112
vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/progress.go

@@ -1,112 +0,0 @@
-package oss
-
-import "io"
-
-// ProgressEventType defines transfer progress event type
-type ProgressEventType int
-
-const (
-	// TransferStartedEvent transfer started, set TotalBytes
-	TransferStartedEvent ProgressEventType = 1 + iota
-	// TransferDataEvent transfer data, set ConsumedBytes anmd TotalBytes
-	TransferDataEvent
-	// TransferCompletedEvent transfer completed
-	TransferCompletedEvent
-	// TransferFailedEvent transfer encounters an error
-	TransferFailedEvent
-)
-
-// ProgressEvent defines progress event
-type ProgressEvent struct {
-	ConsumedBytes int64
-	TotalBytes    int64
-	EventType     ProgressEventType
-}
-
-// ProgressListener listens progress change
-type ProgressListener interface {
-	ProgressChanged(event *ProgressEvent)
-}
-
-// -------------------- Private --------------------
-
-func newProgressEvent(eventType ProgressEventType, consumed, total int64) *ProgressEvent {
-	return &ProgressEvent{
-		ConsumedBytes: consumed,
-		TotalBytes:    total,
-		EventType:     eventType}
-}
-
-// publishProgress
-func publishProgress(listener ProgressListener, event *ProgressEvent) {
-	if listener != nil && event != nil {
-		listener.ProgressChanged(event)
-	}
-}
-
-type readerTracker struct {
-	completedBytes int64
-}
-
-type teeReader struct {
-	reader        io.Reader
-	writer        io.Writer
-	listener      ProgressListener
-	consumedBytes int64
-	totalBytes    int64
-	tracker       *readerTracker
-}
-
-// TeeReader returns a Reader that writes to w what it reads from r.
-// All reads from r performed through it are matched with
-// corresponding writes to w.  There is no internal buffering -
-// the write must complete before the read completes.
-// Any error encountered while writing is reported as a read error.
-func TeeReader(reader io.Reader, writer io.Writer, totalBytes int64, listener ProgressListener, tracker *readerTracker) io.ReadCloser {
-	return &teeReader{
-		reader:        reader,
-		writer:        writer,
-		listener:      listener,
-		consumedBytes: 0,
-		totalBytes:    totalBytes,
-		tracker:       tracker,
-	}
-}
-
-func (t *teeReader) Read(p []byte) (n int, err error) {
-	n, err = t.reader.Read(p)
-
-	// Read encountered error
-	if err != nil && err != io.EOF {
-		event := newProgressEvent(TransferFailedEvent, t.consumedBytes, t.totalBytes)
-		publishProgress(t.listener, event)
-	}
-
-	if n > 0 {
-		t.consumedBytes += int64(n)
-		// CRC
-		if t.writer != nil {
-			if n, err := t.writer.Write(p[:n]); err != nil {
-				return n, err
-			}
-		}
-		// Progress
-		if t.listener != nil {
-			event := newProgressEvent(TransferDataEvent, t.consumedBytes, t.totalBytes)
-			publishProgress(t.listener, event)
-		}
-		// Track
-		if t.tracker != nil {
-			t.tracker.completedBytes = t.consumedBytes
-		}
-	}
-
-	return
-}
-
-func (t *teeReader) Close() error {
-	if rc, ok := t.reader.(io.ReadCloser); ok {
-		return rc.Close()
-	}
-	return nil
-}

+ 0 - 26
vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/transport_1_6.go

@@ -1,26 +0,0 @@
-// +build !go1.7
-
-package oss
-
-import (
-	"net"
-	"net/http"
-)
-
-func newTransport(conn *Conn, config *Config) *http.Transport {
-	httpTimeOut := conn.config.HTTPTimeout
-	httpMaxConns := conn.config.HTTPMaxConns
-	// New Transport
-	transport := &http.Transport{
-		Dial: func(netw, addr string) (net.Conn, error) {
-			conn, err := net.DialTimeout(netw, addr, httpTimeOut.ConnectTimeout)
-			if err != nil {
-				return nil, err
-			}
-			return newTimeoutConn(conn, httpTimeOut.ReadWriteTimeout, httpTimeOut.LongTimeout), nil
-		},
-		MaxIdleConnsPerHost:   httpMaxConns.MaxIdleConnsPerHost,
-		ResponseHeaderTimeout: httpTimeOut.HeaderTimeout,
-	}
-	return transport
-}

+ 0 - 28
vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/transport_1_7.go

@@ -1,28 +0,0 @@
-// +build go1.7
-
-package oss
-
-import (
-	"net"
-	"net/http"
-)
-
-func newTransport(conn *Conn, config *Config) *http.Transport {
-	httpTimeOut := conn.config.HTTPTimeout
-	httpMaxConns := conn.config.HTTPMaxConns
-	// New Transport
-	transport := &http.Transport{
-		Dial: func(netw, addr string) (net.Conn, error) {
-			conn, err := net.DialTimeout(netw, addr, httpTimeOut.ConnectTimeout)
-			if err != nil {
-				return nil, err
-			}
-			return newTimeoutConn(conn, httpTimeOut.ReadWriteTimeout, httpTimeOut.LongTimeout), nil
-		},
-		MaxIdleConns:          httpMaxConns.MaxIdleConns,
-		MaxIdleConnsPerHost:   httpMaxConns.MaxIdleConnsPerHost,
-		IdleConnTimeout:       httpTimeOut.IdleConnTimeout,
-		ResponseHeaderTimeout: httpTimeOut.HeaderTimeout,
-	}
-	return transport
-}

+ 0 - 566
vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/type.go

@@ -1,566 +0,0 @@
-package oss
-
-import (
-	"encoding/xml"
-	"net/url"
-	"time"
-)
-
-// ListBucketsResult defines the result object from ListBuckets request
-type ListBucketsResult struct {
-	XMLName     xml.Name           `xml:"ListAllMyBucketsResult"`
-	Prefix      string             `xml:"Prefix"`         // The prefix in this query
-	Marker      string             `xml:"Marker"`         // The marker filter
-	MaxKeys     int                `xml:"MaxKeys"`        // The max entry count to return. This information is returned when IsTruncated is true.
-	IsTruncated bool               `xml:"IsTruncated"`    // Flag true means there's remaining buckets to return.
-	NextMarker  string             `xml:"NextMarker"`     // The marker filter for the next list call
-	Owner       Owner              `xml:"Owner"`          // The owner information
-	Buckets     []BucketProperties `xml:"Buckets>Bucket"` // The bucket list
-}
-
-// BucketProperties defines bucket properties
-type BucketProperties struct {
-	XMLName      xml.Name  `xml:"Bucket"`
-	Name         string    `xml:"Name"`         // Bucket name
-	Location     string    `xml:"Location"`     // Bucket datacenter
-	CreationDate time.Time `xml:"CreationDate"` // Bucket create time
-	StorageClass string    `xml:"StorageClass"` // Bucket storage class
-}
-
-// GetBucketACLResult defines GetBucketACL request's result
-type GetBucketACLResult struct {
-	XMLName xml.Name `xml:"AccessControlPolicy"`
-	ACL     string   `xml:"AccessControlList>Grant"` // Bucket ACL
-	Owner   Owner    `xml:"Owner"`                   // Bucket owner
-}
-
-// LifecycleConfiguration is the Bucket Lifecycle configuration
-type LifecycleConfiguration struct {
-	XMLName xml.Name        `xml:"LifecycleConfiguration"`
-	Rules   []LifecycleRule `xml:"Rule"`
-}
-
-// LifecycleRule defines Lifecycle rules
-type LifecycleRule struct {
-	XMLName    xml.Name            `xml:"Rule"`
-	ID         string              `xml:"ID"`         // The rule ID
-	Prefix     string              `xml:"Prefix"`     // The object key prefix
-	Status     string              `xml:"Status"`     // The rule status (enabled or not)
-	Expiration LifecycleExpiration `xml:"Expiration"` // The expiration property
-}
-
-// LifecycleExpiration defines the rule's expiration property
-type LifecycleExpiration struct {
-	XMLName xml.Name  `xml:"Expiration"`
-	Days    int       `xml:"Days,omitempty"` // Relative expiration time: The expiration time in days after the last modified time
-	Date    time.Time `xml:"Date,omitempty"` // Absolute expiration time: The expiration time in date.
-}
-
-type lifecycleXML struct {
-	XMLName xml.Name        `xml:"LifecycleConfiguration"`
-	Rules   []lifecycleRule `xml:"Rule"`
-}
-
-type lifecycleRule struct {
-	XMLName    xml.Name            `xml:"Rule"`
-	ID         string              `xml:"ID"`
-	Prefix     string              `xml:"Prefix"`
-	Status     string              `xml:"Status"`
-	Expiration lifecycleExpiration `xml:"Expiration"`
-}
-
-type lifecycleExpiration struct {
-	XMLName xml.Name `xml:"Expiration"`
-	Days    int      `xml:"Days,omitempty"`
-	Date    string   `xml:"Date,omitempty"`
-}
-
-const expirationDateFormat = "2006-01-02T15:04:05.000Z"
-
-func convLifecycleRule(rules []LifecycleRule) []lifecycleRule {
-	rs := []lifecycleRule{}
-	for _, rule := range rules {
-		r := lifecycleRule{}
-		r.ID = rule.ID
-		r.Prefix = rule.Prefix
-		r.Status = rule.Status
-		if rule.Expiration.Date.IsZero() {
-			r.Expiration.Days = rule.Expiration.Days
-		} else {
-			r.Expiration.Date = rule.Expiration.Date.Format(expirationDateFormat)
-		}
-		rs = append(rs, r)
-	}
-	return rs
-}
-
-// BuildLifecycleRuleByDays builds a lifecycle rule with specified expiration days
-func BuildLifecycleRuleByDays(id, prefix string, status bool, days int) LifecycleRule {
-	var statusStr = "Enabled"
-	if !status {
-		statusStr = "Disabled"
-	}
-	return LifecycleRule{ID: id, Prefix: prefix, Status: statusStr,
-		Expiration: LifecycleExpiration{Days: days}}
-}
-
-// BuildLifecycleRuleByDate builds a lifecycle rule with specified expiration time.
-func BuildLifecycleRuleByDate(id, prefix string, status bool, year, month, day int) LifecycleRule {
-	var statusStr = "Enabled"
-	if !status {
-		statusStr = "Disabled"
-	}
-	date := time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.UTC)
-	return LifecycleRule{ID: id, Prefix: prefix, Status: statusStr,
-		Expiration: LifecycleExpiration{Date: date}}
-}
-
-// GetBucketLifecycleResult defines GetBucketLifecycle's result object
-type GetBucketLifecycleResult LifecycleConfiguration
-
-// RefererXML defines Referer configuration
-type RefererXML struct {
-	XMLName           xml.Name `xml:"RefererConfiguration"`
-	AllowEmptyReferer bool     `xml:"AllowEmptyReferer"`   // Allow empty referrer
-	RefererList       []string `xml:"RefererList>Referer"` // Referer whitelist
-}
-
-// GetBucketRefererResult defines result object for GetBucketReferer request
-type GetBucketRefererResult RefererXML
-
-// LoggingXML defines logging configuration
-type LoggingXML struct {
-	XMLName        xml.Name       `xml:"BucketLoggingStatus"`
-	LoggingEnabled LoggingEnabled `xml:"LoggingEnabled"` // The logging configuration information
-}
-
-type loggingXMLEmpty struct {
-	XMLName xml.Name `xml:"BucketLoggingStatus"`
-}
-
-// LoggingEnabled defines the logging configuration information
-type LoggingEnabled struct {
-	XMLName      xml.Name `xml:"LoggingEnabled"`
-	TargetBucket string   `xml:"TargetBucket"` // The bucket name for storing the log files
-	TargetPrefix string   `xml:"TargetPrefix"` // The log file prefix
-}
-
-// GetBucketLoggingResult defines the result from GetBucketLogging request
-type GetBucketLoggingResult LoggingXML
-
-// WebsiteXML defines Website configuration
-type WebsiteXML struct {
-	XMLName       xml.Name      `xml:"WebsiteConfiguration"`
-	IndexDocument IndexDocument `xml:"IndexDocument"` // The index page
-	ErrorDocument ErrorDocument `xml:"ErrorDocument"` // The error page
-}
-
-// IndexDocument defines the index page info
-type IndexDocument struct {
-	XMLName xml.Name `xml:"IndexDocument"`
-	Suffix  string   `xml:"Suffix"` // The file name for the index page
-}
-
-// ErrorDocument defines the 404 error page info
-type ErrorDocument struct {
-	XMLName xml.Name `xml:"ErrorDocument"`
-	Key     string   `xml:"Key"` // 404 error file name
-}
-
-// GetBucketWebsiteResult defines the result from GetBucketWebsite request.
-type GetBucketWebsiteResult WebsiteXML
-
-// CORSXML defines CORS configuration
-type CORSXML struct {
-	XMLName   xml.Name   `xml:"CORSConfiguration"`
-	CORSRules []CORSRule `xml:"CORSRule"` // CORS rules
-}
-
-// CORSRule defines CORS rules
-type CORSRule struct {
-	XMLName       xml.Name `xml:"CORSRule"`
-	AllowedOrigin []string `xml:"AllowedOrigin"` // Allowed origins. By default it's wildcard '*'
-	AllowedMethod []string `xml:"AllowedMethod"` // Allowed methods
-	AllowedHeader []string `xml:"AllowedHeader"` // Allowed headers
-	ExposeHeader  []string `xml:"ExposeHeader"`  // Allowed response headers
-	MaxAgeSeconds int      `xml:"MaxAgeSeconds"` // Max cache ages in seconds
-}
-
-// GetBucketCORSResult defines the result from GetBucketCORS request.
-type GetBucketCORSResult CORSXML
-
-// GetBucketInfoResult defines the result from GetBucketInfo request.
-type GetBucketInfoResult struct {
-	XMLName    xml.Name   `xml:"BucketInfo"`
-	BucketInfo BucketInfo `xml:"Bucket"`
-}
-
-// BucketInfo defines Bucket information
-type BucketInfo struct {
-	XMLName          xml.Name  `xml:"Bucket"`
-	Name             string    `xml:"Name"`                    // Bucket name
-	Location         string    `xml:"Location"`                // Bucket datacenter
-	CreationDate     time.Time `xml:"CreationDate"`            // Bucket creation time
-	ExtranetEndpoint string    `xml:"ExtranetEndpoint"`        // Bucket external endpoint
-	IntranetEndpoint string    `xml:"IntranetEndpoint"`        // Bucket internal endpoint
-	ACL              string    `xml:"AccessControlList>Grant"` // Bucket ACL
-	Owner            Owner     `xml:"Owner"`                   // Bucket owner
-	StorageClass     string    `xml:"StorageClass"`            // Bucket storage class
-}
-
-// ListObjectsResult defines the result from ListObjects request
-type ListObjectsResult struct {
-	XMLName        xml.Name           `xml:"ListBucketResult"`
-	Prefix         string             `xml:"Prefix"`                // The object prefix
-	Marker         string             `xml:"Marker"`                // The marker filter.
-	MaxKeys        int                `xml:"MaxKeys"`               // Max keys to return
-	Delimiter      string             `xml:"Delimiter"`             // The delimiter for grouping objects' name
-	IsTruncated    bool               `xml:"IsTruncated"`           // Flag indicates if all results are returned (when it's false)
-	NextMarker     string             `xml:"NextMarker"`            // The start point of the next query
-	Objects        []ObjectProperties `xml:"Contents"`              // Object list
-	CommonPrefixes []string           `xml:"CommonPrefixes>Prefix"` // You can think of commonprefixes as "folders" whose names end with the delimiter
-}
-
-// ObjectProperties defines Objecct properties
-type ObjectProperties struct {
-	XMLName      xml.Name  `xml:"Contents"`
-	Key          string    `xml:"Key"`          // Object key
-	Type         string    `xml:"Type"`         // Object type
-	Size         int64     `xml:"Size"`         // Object size
-	ETag         string    `xml:"ETag"`         // Object ETag
-	Owner        Owner     `xml:"Owner"`        // Object owner information
-	LastModified time.Time `xml:"LastModified"` // Object last modified time
-	StorageClass string    `xml:"StorageClass"` // Object storage class (Standard, IA, Archive)
-}
-
-// Owner defines Bucket/Object's owner
-type Owner struct {
-	XMLName     xml.Name `xml:"Owner"`
-	ID          string   `xml:"ID"`          // Owner ID
-	DisplayName string   `xml:"DisplayName"` // Owner's display name
-}
-
-// CopyObjectResult defines result object of CopyObject
-type CopyObjectResult struct {
-	XMLName      xml.Name  `xml:"CopyObjectResult"`
-	LastModified time.Time `xml:"LastModified"` // New object's last modified time.
-	ETag         string    `xml:"ETag"`         // New object's ETag
-}
-
-// GetObjectACLResult defines result of GetObjectACL request
-type GetObjectACLResult GetBucketACLResult
-
-type deleteXML struct {
-	XMLName xml.Name       `xml:"Delete"`
-	Objects []DeleteObject `xml:"Object"` // Objects to delete
-	Quiet   bool           `xml:"Quiet"`  // Flag of quiet mode.
-}
-
-// DeleteObject defines the struct for deleting object
-type DeleteObject struct {
-	XMLName xml.Name `xml:"Object"`
-	Key     string   `xml:"Key"` // Object name
-}
-
-// DeleteObjectsResult defines result of DeleteObjects request
-type DeleteObjectsResult struct {
-	XMLName        xml.Name `xml:"DeleteResult"`
-	DeletedObjects []string `xml:"Deleted>Key"` // Deleted object list
-}
-
-// InitiateMultipartUploadResult defines result of InitiateMultipartUpload request
-type InitiateMultipartUploadResult struct {
-	XMLName  xml.Name `xml:"InitiateMultipartUploadResult"`
-	Bucket   string   `xml:"Bucket"`   // Bucket name
-	Key      string   `xml:"Key"`      // Object name to upload
-	UploadID string   `xml:"UploadId"` // Generated UploadId
-}
-
-// UploadPart defines the upload/copy part
-type UploadPart struct {
-	XMLName    xml.Name `xml:"Part"`
-	PartNumber int      `xml:"PartNumber"` // Part number
-	ETag       string   `xml:"ETag"`       // ETag value of the part's data
-}
-
-type uploadParts []UploadPart
-
-func (slice uploadParts) Len() int {
-	return len(slice)
-}
-
-func (slice uploadParts) Less(i, j int) bool {
-	return slice[i].PartNumber < slice[j].PartNumber
-}
-
-func (slice uploadParts) Swap(i, j int) {
-	slice[i], slice[j] = slice[j], slice[i]
-}
-
-// UploadPartCopyResult defines result object of multipart copy request.
-type UploadPartCopyResult struct {
-	XMLName      xml.Name  `xml:"CopyPartResult"`
-	LastModified time.Time `xml:"LastModified"` // Last modified time
-	ETag         string    `xml:"ETag"`         // ETag
-}
-
-type completeMultipartUploadXML struct {
-	XMLName xml.Name     `xml:"CompleteMultipartUpload"`
-	Part    []UploadPart `xml:"Part"`
-}
-
-// CompleteMultipartUploadResult defines result object of CompleteMultipartUploadRequest
-type CompleteMultipartUploadResult struct {
-	XMLName  xml.Name `xml:"CompleteMultipartUploadResult"`
-	Location string   `xml:"Location"` // Object URL
-	Bucket   string   `xml:"Bucket"`   // Bucket name
-	ETag     string   `xml:"ETag"`     // Object ETag
-	Key      string   `xml:"Key"`      // Object name
-}
-
-// ListUploadedPartsResult defines result object of ListUploadedParts
-type ListUploadedPartsResult struct {
-	XMLName              xml.Name       `xml:"ListPartsResult"`
-	Bucket               string         `xml:"Bucket"`               // Bucket name
-	Key                  string         `xml:"Key"`                  // Object name
-	UploadID             string         `xml:"UploadId"`             // Upload ID
-	NextPartNumberMarker string         `xml:"NextPartNumberMarker"` // Next part number
-	MaxParts             int            `xml:"MaxParts"`             // Max parts count
-	IsTruncated          bool           `xml:"IsTruncated"`          // Flag indicates all entries returned.false: all entries returned.
-	UploadedParts        []UploadedPart `xml:"Part"`                 // Uploaded parts
-}
-
-// UploadedPart defines uploaded part
-type UploadedPart struct {
-	XMLName      xml.Name  `xml:"Part"`
-	PartNumber   int       `xml:"PartNumber"`   // Part number
-	LastModified time.Time `xml:"LastModified"` // Last modified time
-	ETag         string    `xml:"ETag"`         // ETag cache
-	Size         int       `xml:"Size"`         // Part size
-}
-
-// ListMultipartUploadResult defines result object of ListMultipartUpload
-type ListMultipartUploadResult struct {
-	XMLName            xml.Name            `xml:"ListMultipartUploadsResult"`
-	Bucket             string              `xml:"Bucket"`                // Bucket name
-	Delimiter          string              `xml:"Delimiter"`             // Delimiter for grouping object.
-	Prefix             string              `xml:"Prefix"`                // Object prefix
-	KeyMarker          string              `xml:"KeyMarker"`             // Object key marker
-	UploadIDMarker     string              `xml:"UploadIdMarker"`        // UploadId marker
-	NextKeyMarker      string              `xml:"NextKeyMarker"`         // Next key marker, if not all entries returned.
-	NextUploadIDMarker string              `xml:"NextUploadIdMarker"`    // Next uploadId marker, if not all entries returned.
-	MaxUploads         int                 `xml:"MaxUploads"`            // Max uploads to return
-	IsTruncated        bool                `xml:"IsTruncated"`           // Flag indicates all entries are returned.
-	Uploads            []UncompletedUpload `xml:"Upload"`                // Ongoing uploads (not completed, not aborted)
-	CommonPrefixes     []string            `xml:"CommonPrefixes>Prefix"` // Common prefixes list.
-}
-
-// UncompletedUpload structure wraps an uncompleted upload task
-type UncompletedUpload struct {
-	XMLName   xml.Name  `xml:"Upload"`
-	Key       string    `xml:"Key"`       // Object name
-	UploadID  string    `xml:"UploadId"`  // The UploadId
-	Initiated time.Time `xml:"Initiated"` // Initialization time in the format such as 2012-02-23T04:18:23.000Z
-}
-
-// ProcessObjectResult defines result object of ProcessObject
-type ProcessObjectResult struct {
-	Bucket   string `json:"bucket"`
-	FileSize int    `json:"fileSize"`
-	Object   string `json:"object"`
-	Status   string `json:"status"`
-}
-
-// decodeDeleteObjectsResult decodes deleting objects result in URL encoding
-func decodeDeleteObjectsResult(result *DeleteObjectsResult) error {
-	var err error
-	for i := 0; i < len(result.DeletedObjects); i++ {
-		result.DeletedObjects[i], err = url.QueryUnescape(result.DeletedObjects[i])
-		if err != nil {
-			return err
-		}
-	}
-	return nil
-}
-
-// decodeListObjectsResult decodes list objects result in URL encoding
-func decodeListObjectsResult(result *ListObjectsResult) error {
-	var err error
-	result.Prefix, err = url.QueryUnescape(result.Prefix)
-	if err != nil {
-		return err
-	}
-	result.Marker, err = url.QueryUnescape(result.Marker)
-	if err != nil {
-		return err
-	}
-	result.Delimiter, err = url.QueryUnescape(result.Delimiter)
-	if err != nil {
-		return err
-	}
-	result.NextMarker, err = url.QueryUnescape(result.NextMarker)
-	if err != nil {
-		return err
-	}
-	for i := 0; i < len(result.Objects); i++ {
-		result.Objects[i].Key, err = url.QueryUnescape(result.Objects[i].Key)
-		if err != nil {
-			return err
-		}
-	}
-	for i := 0; i < len(result.CommonPrefixes); i++ {
-		result.CommonPrefixes[i], err = url.QueryUnescape(result.CommonPrefixes[i])
-		if err != nil {
-			return err
-		}
-	}
-	return nil
-}
-
-// decodeListUploadedPartsResult decodes
-func decodeListUploadedPartsResult(result *ListUploadedPartsResult) error {
-	var err error
-	result.Key, err = url.QueryUnescape(result.Key)
-	if err != nil {
-		return err
-	}
-	return nil
-}
-
-// decodeListMultipartUploadResult decodes list multipart upload result in URL encoding
-func decodeListMultipartUploadResult(result *ListMultipartUploadResult) error {
-	var err error
-	result.Prefix, err = url.QueryUnescape(result.Prefix)
-	if err != nil {
-		return err
-	}
-	result.Delimiter, err = url.QueryUnescape(result.Delimiter)
-	if err != nil {
-		return err
-	}
-	result.KeyMarker, err = url.QueryUnescape(result.KeyMarker)
-	if err != nil {
-		return err
-	}
-	result.NextKeyMarker, err = url.QueryUnescape(result.NextKeyMarker)
-	if err != nil {
-		return err
-	}
-	for i := 0; i < len(result.Uploads); i++ {
-		result.Uploads[i].Key, err = url.QueryUnescape(result.Uploads[i].Key)
-		if err != nil {
-			return err
-		}
-	}
-	for i := 0; i < len(result.CommonPrefixes); i++ {
-		result.CommonPrefixes[i], err = url.QueryUnescape(result.CommonPrefixes[i])
-		if err != nil {
-			return err
-		}
-	}
-	return nil
-}
-
-// createBucketConfiguration defines the configuration for creating a bucket.
-type createBucketConfiguration struct {
-	XMLName      xml.Name         `xml:"CreateBucketConfiguration"`
-	StorageClass StorageClassType `xml:"StorageClass,omitempty"`
-}
-
-// LiveChannelConfiguration defines the configuration for live-channel
-type LiveChannelConfiguration struct {
-	XMLName     xml.Name          `xml:"LiveChannelConfiguration"`
-	Description string            `xml:"Description,omitempty"` //Description of live-channel, up to 128 bytes
-	Status      string            `xml:"Status,omitempty"`      //Specify the status of livechannel
-	Target      LiveChannelTarget `xml:"Target"`                //target configuration of live-channel
-	// use point instead of struct to avoid omit empty snapshot
-	Snapshot *LiveChannelSnapshot `xml:"Snapshot,omitempty"` //snapshot configuration of live-channel
-}
-
-// LiveChannelTarget target configuration of live-channel
-type LiveChannelTarget struct {
-	XMLName      xml.Name `xml:"Target"`
-	Type         string   `xml:"Type"`                   //the type of object, only supports HLS
-	FragDuration int      `xml:"FragDuration,omitempty"` //the length of each ts object (in seconds), in the range [1,100]
-	FragCount    int      `xml:"FragCount,omitempty"`    //the number of ts objects in the m3u8 object, in the range of [1,100]
-	PlaylistName string   `xml:"PlaylistName,omitempty"` //the name of m3u8 object, which must end with ".m3u8" and the length range is [6,128]
-}
-
-// LiveChannelSnapshot snapshot configuration of live-channel
-type LiveChannelSnapshot struct {
-	XMLName     xml.Name `xml:"Snapshot"`
-	RoleName    string   `xml:"RoleName,omitempty"`    //The role of snapshot operations, it sholud has write permission of DestBucket and the permission to send messages to the NotifyTopic.
-	DestBucket  string   `xml:"DestBucket,omitempty"`  //Bucket the snapshots will be written to. should be the same owner as the source bucket.
-	NotifyTopic string   `xml:"NotifyTopic,omitempty"` //Topics of MNS for notifying users of high frequency screenshot operation results
-	Interval    int      `xml:"Interval,omitempty"`    //interval of snapshots, threre is no snapshot if no I-frame during the interval time
-}
-
-// CreateLiveChannelResult the result of crete live-channel
-type CreateLiveChannelResult struct {
-	XMLName     xml.Name `xml:"CreateLiveChannelResult"`
-	PublishUrls []string `xml:"PublishUrls>Url"` //push urls list
-	PlayUrls    []string `xml:"PlayUrls>Url"`    //play urls list
-}
-
-// LiveChannelStat the result of get live-channel state
-type LiveChannelStat struct {
-	XMLName       xml.Name         `xml:"LiveChannelStat"`
-	Status        string           `xml:"Status"`        //Current push status of live-channel: Disabled,Live,Idle
-	ConnectedTime time.Time        `xml:"ConnectedTime"` //The time when the client starts pushing, format: ISO8601
-	RemoteAddr    string           `xml:"RemoteAddr"`    //The ip address of the client
-	Video         LiveChannelVideo `xml:"Video"`         //Video stream information
-	Audio         LiveChannelAudio `xml:"Audio"`         //Audio stream information
-}
-
-// LiveChannelVideo video stream information
-type LiveChannelVideo struct {
-	XMLName   xml.Name `xml:"Video"`
-	Width     int      `xml:"Width"`     //Width (unit: pixels)
-	Height    int      `xml:"Height"`    //Height (unit: pixels)
-	FrameRate int      `xml:"FrameRate"` //FramRate
-	Bandwidth int      `xml:"Bandwidth"` //Bandwidth (unit: B/s)
-}
-
-// LiveChannelAudio audio stream information
-type LiveChannelAudio struct {
-	XMLName    xml.Name `xml:"Audio"`
-	SampleRate int      `xml:"SampleRate"` //SampleRate
-	Bandwidth  int      `xml:"Bandwidth"`  //Bandwidth (unit: B/s)
-	Codec      string   `xml:"Codec"`      //Encoding forma
-}
-
-// LiveChannelHistory the result of GetLiveChannelHistory, at most return up to lastest 10 push records
-type LiveChannelHistory struct {
-	XMLName xml.Name     `xml:"LiveChannelHistory"`
-	Record  []LiveRecord `xml:"LiveRecord"` //push records list
-}
-
-// LiveRecord push recode
-type LiveRecord struct {
-	XMLName    xml.Name  `xml:"LiveRecord"`
-	StartTime  time.Time `xml:"StartTime"`  //StartTime, format: ISO8601
-	EndTime    time.Time `xml:"EndTime"`    //EndTime, format: ISO8601
-	RemoteAddr string    `xml:"RemoteAddr"` //The ip address of remote client
-}
-
-// ListLiveChannelResult the result of ListLiveChannel
-type ListLiveChannelResult struct {
-	XMLName     xml.Name          `xml:"ListLiveChannelResult"`
-	Prefix      string            `xml:"Prefix"`      //Filter by the name start with the value of "Prefix"
-	Marker      string            `xml:"Marker"`      //cursor from which starting list
-	MaxKeys     int               `xml:"MaxKeys"`     //The maximum count returned. the default value is 100. it cannot be greater than 1000.
-	IsTruncated bool              `xml:"IsTruncated"` //Indicates whether all results have been returned, "true" indicates partial results returned while "false" indicates all results have been returned
-	NextMarker  string            `xml:"NextMarker"`  //NextMarker indicate the Marker value of the next request
-	LiveChannel []LiveChannelInfo `xml:"LiveChannel"` //The infomation of live-channel
-}
-
-// LiveChannelInfo the infomation of live-channel
-type LiveChannelInfo struct {
-	XMLName      xml.Name  `xml:"LiveChannel"`
-	Name         string    `xml:"Name"`            //The name of live-channel
-	Description  string    `xml:"Description"`     //Description of live-channel
-	Status       string    `xml:"Status"`          //Status: disabled or enabled
-	LastModified time.Time `xml:"LastModified"`    //Last modification time, format: ISO8601
-	PublishUrls  []string  `xml:"PublishUrls>Url"` //push urls list
-	PlayUrls     []string  `xml:"PlayUrls>Url"`    //play urls list
-}

+ 0 - 526
vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/upload.go

@@ -1,526 +0,0 @@
-package oss
-
-import (
-	"crypto/md5"
-	"encoding/base64"
-	"encoding/hex"
-	"encoding/json"
-	"errors"
-	"fmt"
-	"io/ioutil"
-	"os"
-	"path/filepath"
-	"time"
-)
-
-// UploadFile is multipart file upload.
-//
-// objectKey    the object name.
-// filePath    the local file path to upload.
-// partSize    the part size in byte.
-// options    the options for uploading object.
-//
-// error    it's nil if the operation succeeds, otherwise it's an error object.
-//
-func (bucket Bucket) UploadFile(objectKey, filePath string, partSize int64, options ...Option) error {
-	if partSize < MinPartSize || partSize > MaxPartSize {
-		return errors.New("oss: part size invalid range (100KB, 5GB]")
-	}
-
-	cpConf := getCpConfig(options)
-	routines := getRoutines(options)
-
-	if cpConf != nil && cpConf.IsEnable {
-		cpFilePath := getUploadCpFilePath(cpConf, filePath, bucket.BucketName, objectKey)
-		if cpFilePath != "" {
-			return bucket.uploadFileWithCp(objectKey, filePath, partSize, options, cpFilePath, routines)
-		}
-	}
-
-	return bucket.uploadFile(objectKey, filePath, partSize, options, routines)
-}
-
-func getUploadCpFilePath(cpConf *cpConfig, srcFile, destBucket, destObject string) string {
-	if cpConf.FilePath == "" && cpConf.DirPath != "" {
-		dest := fmt.Sprintf("oss://%v/%v", destBucket, destObject)
-		absPath, _ := filepath.Abs(srcFile)
-		cpFileName := getCpFileName(absPath, dest)
-		cpConf.FilePath = cpConf.DirPath + string(os.PathSeparator) + cpFileName
-	}
-	return cpConf.FilePath
-}
-
-// ----- concurrent upload without checkpoint  -----
-
-// getCpConfig gets checkpoint configuration
-func getCpConfig(options []Option) *cpConfig {
-	cpcOpt, err := findOption(options, checkpointConfig, nil)
-	if err != nil || cpcOpt == nil {
-		return nil
-	}
-
-	return cpcOpt.(*cpConfig)
-}
-
-// getCpFileName return the name of the checkpoint file
-func getCpFileName(src, dest string) string {
-	md5Ctx := md5.New()
-	md5Ctx.Write([]byte(src))
-	srcCheckSum := hex.EncodeToString(md5Ctx.Sum(nil))
-
-	md5Ctx.Reset()
-	md5Ctx.Write([]byte(dest))
-	destCheckSum := hex.EncodeToString(md5Ctx.Sum(nil))
-
-	return fmt.Sprintf("%v-%v.cp", srcCheckSum, destCheckSum)
-}
-
-// getRoutines gets the routine count. by default it's 1.
-func getRoutines(options []Option) int {
-	rtnOpt, err := findOption(options, routineNum, nil)
-	if err != nil || rtnOpt == nil {
-		return 1
-	}
-
-	rs := rtnOpt.(int)
-	if rs < 1 {
-		rs = 1
-	} else if rs > 100 {
-		rs = 100
-	}
-
-	return rs
-}
-
-// getPayer return the payer of the request
-func getPayer(options []Option) string {
-	payerOpt, err := findOption(options, HTTPHeaderOSSRequester, nil)
-	if err != nil || payerOpt == nil {
-		return ""
-	}
-
-	return payerOpt.(string)
-}
-
-// getProgressListener gets the progress callback
-func getProgressListener(options []Option) ProgressListener {
-	isSet, listener, _ := isOptionSet(options, progressListener)
-	if !isSet {
-		return nil
-	}
-	return listener.(ProgressListener)
-}
-
-// uploadPartHook is for testing usage
-type uploadPartHook func(id int, chunk FileChunk) error
-
-var uploadPartHooker uploadPartHook = defaultUploadPart
-
-func defaultUploadPart(id int, chunk FileChunk) error {
-	return nil
-}
-
-// workerArg defines worker argument structure
-type workerArg struct {
-	bucket   *Bucket
-	filePath string
-	imur     InitiateMultipartUploadResult
-	options  []Option
-	hook     uploadPartHook
-}
-
-// worker is the worker coroutine function
-func worker(id int, arg workerArg, jobs <-chan FileChunk, results chan<- UploadPart, failed chan<- error, die <-chan bool) {
-	for chunk := range jobs {
-		if err := arg.hook(id, chunk); err != nil {
-			failed <- err
-			break
-		}
-		part, err := arg.bucket.UploadPartFromFile(arg.imur, arg.filePath, chunk.Offset, chunk.Size, chunk.Number, arg.options...)
-		if err != nil {
-			failed <- err
-			break
-		}
-		select {
-		case <-die:
-			return
-		default:
-		}
-		results <- part
-	}
-}
-
-// scheduler function
-func scheduler(jobs chan FileChunk, chunks []FileChunk) {
-	for _, chunk := range chunks {
-		jobs <- chunk
-	}
-	close(jobs)
-}
-
-func getTotalBytes(chunks []FileChunk) int64 {
-	var tb int64
-	for _, chunk := range chunks {
-		tb += chunk.Size
-	}
-	return tb
-}
-
-// uploadFile is a concurrent upload, without checkpoint
-func (bucket Bucket) uploadFile(objectKey, filePath string, partSize int64, options []Option, routines int) error {
-	listener := getProgressListener(options)
-
-	chunks, err := SplitFileByPartSize(filePath, partSize)
-	if err != nil {
-		return err
-	}
-
-	payerOptions := []Option{}
-	payer := getPayer(options)
-	if payer != "" {
-		payerOptions = append(payerOptions, RequestPayer(PayerType(payer)))
-	}
-
-	// Initialize the multipart upload
-	imur, err := bucket.InitiateMultipartUpload(objectKey, options...)
-	if err != nil {
-		return err
-	}
-
-	jobs := make(chan FileChunk, len(chunks))
-	results := make(chan UploadPart, len(chunks))
-	failed := make(chan error)
-	die := make(chan bool)
-
-	var completedBytes int64
-	totalBytes := getTotalBytes(chunks)
-	event := newProgressEvent(TransferStartedEvent, 0, totalBytes)
-	publishProgress(listener, event)
-
-	// Start the worker coroutine
-	arg := workerArg{&bucket, filePath, imur, payerOptions, uploadPartHooker}
-	for w := 1; w <= routines; w++ {
-		go worker(w, arg, jobs, results, failed, die)
-	}
-
-	// Schedule the jobs
-	go scheduler(jobs, chunks)
-
-	// Waiting for the upload finished
-	completed := 0
-	parts := make([]UploadPart, len(chunks))
-	for completed < len(chunks) {
-		select {
-		case part := <-results:
-			completed++
-			parts[part.PartNumber-1] = part
-			completedBytes += chunks[part.PartNumber-1].Size
-			event = newProgressEvent(TransferDataEvent, completedBytes, totalBytes)
-			publishProgress(listener, event)
-		case err := <-failed:
-			close(die)
-			event = newProgressEvent(TransferFailedEvent, completedBytes, totalBytes)
-			publishProgress(listener, event)
-			bucket.AbortMultipartUpload(imur, payerOptions...)
-			return err
-		}
-
-		if completed >= len(chunks) {
-			break
-		}
-	}
-
-	event = newProgressEvent(TransferStartedEvent, completedBytes, totalBytes)
-	publishProgress(listener, event)
-
-	// Complete the multpart upload
-	_, err = bucket.CompleteMultipartUpload(imur, parts, payerOptions...)
-	if err != nil {
-		bucket.AbortMultipartUpload(imur, payerOptions...)
-		return err
-	}
-	return nil
-}
-
-// ----- concurrent upload with checkpoint  -----
-const uploadCpMagic = "FE8BB4EA-B593-4FAC-AD7A-2459A36E2E62"
-
-type uploadCheckpoint struct {
-	Magic     string   // Magic
-	MD5       string   // Checkpoint file content's MD5
-	FilePath  string   // Local file path
-	FileStat  cpStat   // File state
-	ObjectKey string   // Key
-	UploadID  string   // Upload ID
-	Parts     []cpPart // All parts of the local file
-}
-
-type cpStat struct {
-	Size         int64     // File size
-	LastModified time.Time // File's last modified time
-	MD5          string    // Local file's MD5
-}
-
-type cpPart struct {
-	Chunk       FileChunk  // File chunk
-	Part        UploadPart // Uploaded part
-	IsCompleted bool       // Upload complete flag
-}
-
-// isValid checks if the uploaded data is valid---it's valid when the file is not updated and the checkpoint data is valid.
-func (cp uploadCheckpoint) isValid(filePath string) (bool, error) {
-	// Compare the CP's magic number and MD5.
-	cpb := cp
-	cpb.MD5 = ""
-	js, _ := json.Marshal(cpb)
-	sum := md5.Sum(js)
-	b64 := base64.StdEncoding.EncodeToString(sum[:])
-
-	if cp.Magic != uploadCpMagic || b64 != cp.MD5 {
-		return false, nil
-	}
-
-	// Make sure if the local file is updated.
-	fd, err := os.Open(filePath)
-	if err != nil {
-		return false, err
-	}
-	defer fd.Close()
-
-	st, err := fd.Stat()
-	if err != nil {
-		return false, err
-	}
-
-	md, err := calcFileMD5(filePath)
-	if err != nil {
-		return false, err
-	}
-
-	// Compare the file size, file's last modified time and file's MD5
-	if cp.FileStat.Size != st.Size() ||
-		cp.FileStat.LastModified != st.ModTime() ||
-		cp.FileStat.MD5 != md {
-		return false, nil
-	}
-
-	return true, nil
-}
-
-// load loads from the file
-func (cp *uploadCheckpoint) load(filePath string) error {
-	contents, err := ioutil.ReadFile(filePath)
-	if err != nil {
-		return err
-	}
-
-	err = json.Unmarshal(contents, cp)
-	return err
-}
-
-// dump dumps to the local file
-func (cp *uploadCheckpoint) dump(filePath string) error {
-	bcp := *cp
-
-	// Calculate MD5
-	bcp.MD5 = ""
-	js, err := json.Marshal(bcp)
-	if err != nil {
-		return err
-	}
-	sum := md5.Sum(js)
-	b64 := base64.StdEncoding.EncodeToString(sum[:])
-	bcp.MD5 = b64
-
-	// Serialization
-	js, err = json.Marshal(bcp)
-	if err != nil {
-		return err
-	}
-
-	// Dump
-	return ioutil.WriteFile(filePath, js, FilePermMode)
-}
-
-// updatePart updates the part status
-func (cp *uploadCheckpoint) updatePart(part UploadPart) {
-	cp.Parts[part.PartNumber-1].Part = part
-	cp.Parts[part.PartNumber-1].IsCompleted = true
-}
-
-// todoParts returns unfinished parts
-func (cp *uploadCheckpoint) todoParts() []FileChunk {
-	fcs := []FileChunk{}
-	for _, part := range cp.Parts {
-		if !part.IsCompleted {
-			fcs = append(fcs, part.Chunk)
-		}
-	}
-	return fcs
-}
-
-// allParts returns all parts
-func (cp *uploadCheckpoint) allParts() []UploadPart {
-	ps := []UploadPart{}
-	for _, part := range cp.Parts {
-		ps = append(ps, part.Part)
-	}
-	return ps
-}
-
-// getCompletedBytes returns completed bytes count
-func (cp *uploadCheckpoint) getCompletedBytes() int64 {
-	var completedBytes int64
-	for _, part := range cp.Parts {
-		if part.IsCompleted {
-			completedBytes += part.Chunk.Size
-		}
-	}
-	return completedBytes
-}
-
-// calcFileMD5 calculates the MD5 for the specified local file
-func calcFileMD5(filePath string) (string, error) {
-	return "", nil
-}
-
-// prepare initializes the multipart upload
-func prepare(cp *uploadCheckpoint, objectKey, filePath string, partSize int64, bucket *Bucket, options []Option) error {
-	// CP
-	cp.Magic = uploadCpMagic
-	cp.FilePath = filePath
-	cp.ObjectKey = objectKey
-
-	// Local file
-	fd, err := os.Open(filePath)
-	if err != nil {
-		return err
-	}
-	defer fd.Close()
-
-	st, err := fd.Stat()
-	if err != nil {
-		return err
-	}
-	cp.FileStat.Size = st.Size()
-	cp.FileStat.LastModified = st.ModTime()
-	md, err := calcFileMD5(filePath)
-	if err != nil {
-		return err
-	}
-	cp.FileStat.MD5 = md
-
-	// Chunks
-	parts, err := SplitFileByPartSize(filePath, partSize)
-	if err != nil {
-		return err
-	}
-
-	cp.Parts = make([]cpPart, len(parts))
-	for i, part := range parts {
-		cp.Parts[i].Chunk = part
-		cp.Parts[i].IsCompleted = false
-	}
-
-	// Init load
-	imur, err := bucket.InitiateMultipartUpload(objectKey, options...)
-	if err != nil {
-		return err
-	}
-	cp.UploadID = imur.UploadID
-
-	return nil
-}
-
-// complete completes the multipart upload and deletes the local CP files
-func complete(cp *uploadCheckpoint, bucket *Bucket, parts []UploadPart, cpFilePath string, options []Option) error {
-	imur := InitiateMultipartUploadResult{Bucket: bucket.BucketName,
-		Key: cp.ObjectKey, UploadID: cp.UploadID}
-	_, err := bucket.CompleteMultipartUpload(imur, parts, options...)
-	if err != nil {
-		return err
-	}
-	os.Remove(cpFilePath)
-	return err
-}
-
-// uploadFileWithCp handles concurrent upload with checkpoint
-func (bucket Bucket) uploadFileWithCp(objectKey, filePath string, partSize int64, options []Option, cpFilePath string, routines int) error {
-	listener := getProgressListener(options)
-
-	payerOptions := []Option{}
-	payer := getPayer(options)
-	if payer != "" {
-		payerOptions = append(payerOptions, RequestPayer(PayerType(payer)))
-	}
-
-	// Load CP data
-	ucp := uploadCheckpoint{}
-	err := ucp.load(cpFilePath)
-	if err != nil {
-		os.Remove(cpFilePath)
-	}
-
-	// Load error or the CP data is invalid.
-	valid, err := ucp.isValid(filePath)
-	if err != nil || !valid {
-		if err = prepare(&ucp, objectKey, filePath, partSize, &bucket, options); err != nil {
-			return err
-		}
-		os.Remove(cpFilePath)
-	}
-
-	chunks := ucp.todoParts()
-	imur := InitiateMultipartUploadResult{
-		Bucket:   bucket.BucketName,
-		Key:      objectKey,
-		UploadID: ucp.UploadID}
-
-	jobs := make(chan FileChunk, len(chunks))
-	results := make(chan UploadPart, len(chunks))
-	failed := make(chan error)
-	die := make(chan bool)
-
-	completedBytes := ucp.getCompletedBytes()
-	event := newProgressEvent(TransferStartedEvent, completedBytes, ucp.FileStat.Size)
-	publishProgress(listener, event)
-
-	// Start the workers
-	arg := workerArg{&bucket, filePath, imur, payerOptions, uploadPartHooker}
-	for w := 1; w <= routines; w++ {
-		go worker(w, arg, jobs, results, failed, die)
-	}
-
-	// Schedule jobs
-	go scheduler(jobs, chunks)
-
-	// Waiting for the job finished
-	completed := 0
-	for completed < len(chunks) {
-		select {
-		case part := <-results:
-			completed++
-			ucp.updatePart(part)
-			ucp.dump(cpFilePath)
-			completedBytes += ucp.Parts[part.PartNumber-1].Chunk.Size
-			event = newProgressEvent(TransferDataEvent, completedBytes, ucp.FileStat.Size)
-			publishProgress(listener, event)
-		case err := <-failed:
-			close(die)
-			event = newProgressEvent(TransferFailedEvent, completedBytes, ucp.FileStat.Size)
-			publishProgress(listener, event)
-			return err
-		}
-
-		if completed >= len(chunks) {
-			break
-		}
-	}
-
-	event = newProgressEvent(TransferCompletedEvent, completedBytes, ucp.FileStat.Size)
-	publishProgress(listener, event)
-
-	// Complete the multipart upload
-	err = complete(&ucp, &bucket, ucp.allParts(), cpFilePath, payerOptions)
-	return err
-}

+ 0 - 265
vendor/github.com/aliyun/aliyun-oss-go-sdk/oss/utils.go

@@ -1,265 +0,0 @@
-package oss
-
-import (
-	"bytes"
-	"errors"
-	"fmt"
-	"hash/crc64"
-	"net/http"
-	"os"
-	"os/exec"
-	"runtime"
-	"strconv"
-	"strings"
-	"time"
-)
-
-// userAgent gets user agent
-// It has the SDK version information, OS information and GO version
-func userAgent() string {
-	sys := getSysInfo()
-	return fmt.Sprintf("aliyun-sdk-go/%s (%s/%s/%s;%s)", Version, sys.name,
-		sys.release, sys.machine, runtime.Version())
-}
-
-type sysInfo struct {
-	name    string // OS name such as windows/Linux
-	release string // OS version 2.6.32-220.23.2.ali1089.el5.x86_64 etc
-	machine string // CPU type amd64/x86_64
-}
-
-// getSysInfo gets system info
-// gets the OS information and CPU type
-func getSysInfo() sysInfo {
-	name := runtime.GOOS
-	release := "-"
-	machine := runtime.GOARCH
-	if out, err := exec.Command("uname", "-s").CombinedOutput(); err == nil {
-		name = string(bytes.TrimSpace(out))
-	}
-	if out, err := exec.Command("uname", "-r").CombinedOutput(); err == nil {
-		release = string(bytes.TrimSpace(out))
-	}
-	if out, err := exec.Command("uname", "-m").CombinedOutput(); err == nil {
-		machine = string(bytes.TrimSpace(out))
-	}
-	return sysInfo{name: name, release: release, machine: machine}
-}
-
-// unpackedRange
-type unpackedRange struct {
-	hasStart bool  // Flag indicates if the start point is specified
-	hasEnd   bool  // Flag indicates if the end point is specified
-	start    int64 // Start point
-	end      int64 // End point
-}
-
-// invalidRangeError returns invalid range error
-func invalidRangeError(r string) error {
-	return fmt.Errorf("InvalidRange %s", r)
-}
-
-// parseRange parse various styles of range such as bytes=M-N
-func parseRange(normalizedRange string) (*unpackedRange, error) {
-	var err error
-	hasStart := false
-	hasEnd := false
-	var start int64
-	var end int64
-
-	// Bytes==M-N or ranges=M-N
-	nrSlice := strings.Split(normalizedRange, "=")
-	if len(nrSlice) != 2 || nrSlice[0] != "bytes" {
-		return nil, invalidRangeError(normalizedRange)
-	}
-
-	// Bytes=M-N,X-Y
-	rSlice := strings.Split(nrSlice[1], ",")
-	rStr := rSlice[0]
-
-	if strings.HasSuffix(rStr, "-") { // M-
-		startStr := rStr[:len(rStr)-1]
-		start, err = strconv.ParseInt(startStr, 10, 64)
-		if err != nil {
-			return nil, invalidRangeError(normalizedRange)
-		}
-		hasStart = true
-	} else if strings.HasPrefix(rStr, "-") { // -N
-		len := rStr[1:]
-		end, err = strconv.ParseInt(len, 10, 64)
-		if err != nil {
-			return nil, invalidRangeError(normalizedRange)
-		}
-		if end == 0 { // -0
-			return nil, invalidRangeError(normalizedRange)
-		}
-		hasEnd = true
-	} else { // M-N
-		valSlice := strings.Split(rStr, "-")
-		if len(valSlice) != 2 {
-			return nil, invalidRangeError(normalizedRange)
-		}
-		start, err = strconv.ParseInt(valSlice[0], 10, 64)
-		if err != nil {
-			return nil, invalidRangeError(normalizedRange)
-		}
-		hasStart = true
-		end, err = strconv.ParseInt(valSlice[1], 10, 64)
-		if err != nil {
-			return nil, invalidRangeError(normalizedRange)
-		}
-		hasEnd = true
-	}
-
-	return &unpackedRange{hasStart, hasEnd, start, end}, nil
-}
-
-// adjustRange returns adjusted range, adjust the range according to the length of the file
-func adjustRange(ur *unpackedRange, size int64) (start, end int64) {
-	if ur == nil {
-		return 0, size
-	}
-
-	if ur.hasStart && ur.hasEnd {
-		start = ur.start
-		end = ur.end + 1
-		if ur.start < 0 || ur.start >= size || ur.end > size || ur.start > ur.end {
-			start = 0
-			end = size
-		}
-	} else if ur.hasStart {
-		start = ur.start
-		end = size
-		if ur.start < 0 || ur.start >= size {
-			start = 0
-		}
-	} else if ur.hasEnd {
-		start = size - ur.end
-		end = size
-		if ur.end < 0 || ur.end > size {
-			start = 0
-			end = size
-		}
-	}
-	return
-}
-
-// GetNowSec returns Unix time, the number of seconds elapsed since January 1, 1970 UTC.
-// gets the current time in Unix time, in seconds.
-func GetNowSec() int64 {
-	return time.Now().Unix()
-}
-
-// GetNowNanoSec returns t as a Unix time, the number of nanoseconds elapsed
-// since January 1, 1970 UTC. The result is undefined if the Unix time
-// in nanoseconds cannot be represented by an int64. Note that this
-// means the result of calling UnixNano on the zero Time is undefined.
-// gets the current time in Unix time, in nanoseconds.
-func GetNowNanoSec() int64 {
-	return time.Now().UnixNano()
-}
-
-// GetNowGMT gets the current time in GMT format.
-func GetNowGMT() string {
-	return time.Now().UTC().Format(http.TimeFormat)
-}
-
-// FileChunk is the file chunk definition
-type FileChunk struct {
-	Number int   // Chunk number
-	Offset int64 // Chunk offset
-	Size   int64 // Chunk size.
-}
-
-// SplitFileByPartNum splits big file into parts by the num of parts.
-// Split the file with specified parts count, returns the split result when error is nil.
-func SplitFileByPartNum(fileName string, chunkNum int) ([]FileChunk, error) {
-	if chunkNum <= 0 || chunkNum > 10000 {
-		return nil, errors.New("chunkNum invalid")
-	}
-
-	file, err := os.Open(fileName)
-	if err != nil {
-		return nil, err
-	}
-	defer file.Close()
-
-	stat, err := file.Stat()
-	if err != nil {
-		return nil, err
-	}
-
-	if int64(chunkNum) > stat.Size() {
-		return nil, errors.New("oss: chunkNum invalid")
-	}
-
-	var chunks []FileChunk
-	var chunk = FileChunk{}
-	var chunkN = (int64)(chunkNum)
-	for i := int64(0); i < chunkN; i++ {
-		chunk.Number = int(i + 1)
-		chunk.Offset = i * (stat.Size() / chunkN)
-		if i == chunkN-1 {
-			chunk.Size = stat.Size()/chunkN + stat.Size()%chunkN
-		} else {
-			chunk.Size = stat.Size() / chunkN
-		}
-		chunks = append(chunks, chunk)
-	}
-
-	return chunks, nil
-}
-
-// SplitFileByPartSize splits big file into parts by the size of parts.
-// Splits the file by the part size. Returns the FileChunk when error is nil.
-func SplitFileByPartSize(fileName string, chunkSize int64) ([]FileChunk, error) {
-	if chunkSize <= 0 {
-		return nil, errors.New("chunkSize invalid")
-	}
-
-	file, err := os.Open(fileName)
-	if err != nil {
-		return nil, err
-	}
-	defer file.Close()
-
-	stat, err := file.Stat()
-	if err != nil {
-		return nil, err
-	}
-	var chunkN = stat.Size() / chunkSize
-	if chunkN >= 10000 {
-		return nil, errors.New("Too many parts, please increase part size")
-	}
-
-	var chunks []FileChunk
-	var chunk = FileChunk{}
-	for i := int64(0); i < chunkN; i++ {
-		chunk.Number = int(i + 1)
-		chunk.Offset = i * chunkSize
-		chunk.Size = chunkSize
-		chunks = append(chunks, chunk)
-	}
-
-	if stat.Size()%chunkSize > 0 {
-		chunk.Number = len(chunks) + 1
-		chunk.Offset = int64(len(chunks)) * chunkSize
-		chunk.Size = stat.Size() % chunkSize
-		chunks = append(chunks, chunk)
-	}
-
-	return chunks, nil
-}
-
-// GetPartEnd calculates the end position
-func GetPartEnd(begin int64, total int64, per int64) int64 {
-	if begin+per > total {
-		return total - 1
-	}
-	return begin + per - 1
-}
-
-// crcTable returns the table constructed from the specified polynomial
-var crcTable = func() *crc64.Table {
-	return crc64.MakeTable(crc64.ECMA)
-}

+ 1 - 1
vendor/github.com/jmespath/go-jmespath/.gitignore

@@ -1,4 +1,4 @@
-/jpgo
+jpgo
 jmespath-fuzz.zip
 cpu.out
 go-jmespath.test

+ 1 - 1
vendor/github.com/jmespath/go-jmespath/Makefile

@@ -35,7 +35,7 @@ buildfuzz:
 	go-fuzz-build github.com/jmespath/go-jmespath/fuzz
 
 fuzz: buildfuzz
-	go-fuzz -bin=./jmespath-fuzz.zip -workdir=fuzz/testdata
+	go-fuzz -bin=./jmespath-fuzz.zip -workdir=fuzz/corpus
 
 bench:
 	go test -bench . -cpuprofile cpu.out

+ 0 - 37
vendor/github.com/jmespath/go-jmespath/api.go

@@ -1,42 +1,5 @@
 package jmespath
 
-import "strconv"
-
-// JMESPath is the epresentation of a compiled JMES path query. A JMESPath is
-// safe for concurrent use by multiple goroutines.
-type JMESPath struct {
-	ast  ASTNode
-	intr *treeInterpreter
-}
-
-// Compile parses a JMESPath expression and returns, if successful, a JMESPath
-// object that can be used to match against data.
-func Compile(expression string) (*JMESPath, error) {
-	parser := NewParser()
-	ast, err := parser.Parse(expression)
-	if err != nil {
-		return nil, err
-	}
-	jmespath := &JMESPath{ast: ast, intr: newInterpreter()}
-	return jmespath, nil
-}
-
-// MustCompile is like Compile but panics if the expression cannot be parsed.
-// It simplifies safe initialization of global variables holding compiled
-// JMESPaths.
-func MustCompile(expression string) *JMESPath {
-	jmespath, err := Compile(expression)
-	if err != nil {
-		panic(`jmespath: Compile(` + strconv.Quote(expression) + `): ` + err.Error())
-	}
-	return jmespath
-}
-
-// Search evaluates a JMESPath expression against input data and returns the result.
-func (jp *JMESPath) Search(data interface{}) (interface{}, error) {
-	return jp.intr.Execute(jp.ast, data)
-}
-
 // Search evaluates a JMESPath expression against input data and returns the result.
 func Search(expression string, data interface{}) (interface{}, error) {
 	intr := newInterpreter()

+ 63 - 65
vendor/github.com/jmespath/go-jmespath/functions.go

@@ -5,7 +5,6 @@ import (
 	"errors"
 	"fmt"
 	"math"
-	"reflect"
 	"sort"
 	"strconv"
 	"strings"
@@ -125,197 +124,197 @@ type functionCaller struct {
 func newFunctionCaller() *functionCaller {
 	caller := &functionCaller{}
 	caller.functionTable = map[string]functionEntry{
-		"length": {
+		"length": functionEntry{
 			name: "length",
 			arguments: []argSpec{
-				{types: []jpType{jpString, jpArray, jpObject}},
+				argSpec{types: []jpType{jpString, jpArray, jpObject}},
 			},
 			handler: jpfLength,
 		},
-		"starts_with": {
+		"starts_with": functionEntry{
 			name: "starts_with",
 			arguments: []argSpec{
-				{types: []jpType{jpString}},
-				{types: []jpType{jpString}},
+				argSpec{types: []jpType{jpString}},
+				argSpec{types: []jpType{jpString}},
 			},
 			handler: jpfStartsWith,
 		},
-		"abs": {
+		"abs": functionEntry{
 			name: "abs",
 			arguments: []argSpec{
-				{types: []jpType{jpNumber}},
+				argSpec{types: []jpType{jpNumber}},
 			},
 			handler: jpfAbs,
 		},
-		"avg": {
+		"avg": functionEntry{
 			name: "avg",
 			arguments: []argSpec{
-				{types: []jpType{jpArrayNumber}},
+				argSpec{types: []jpType{jpArrayNumber}},
 			},
 			handler: jpfAvg,
 		},
-		"ceil": {
+		"ceil": functionEntry{
 			name: "ceil",
 			arguments: []argSpec{
-				{types: []jpType{jpNumber}},
+				argSpec{types: []jpType{jpNumber}},
 			},
 			handler: jpfCeil,
 		},
-		"contains": {
+		"contains": functionEntry{
 			name: "contains",
 			arguments: []argSpec{
-				{types: []jpType{jpArray, jpString}},
-				{types: []jpType{jpAny}},
+				argSpec{types: []jpType{jpArray, jpString}},
+				argSpec{types: []jpType{jpAny}},
 			},
 			handler: jpfContains,
 		},
-		"ends_with": {
+		"ends_with": functionEntry{
 			name: "ends_with",
 			arguments: []argSpec{
-				{types: []jpType{jpString}},
-				{types: []jpType{jpString}},
+				argSpec{types: []jpType{jpString}},
+				argSpec{types: []jpType{jpString}},
 			},
 			handler: jpfEndsWith,
 		},
-		"floor": {
+		"floor": functionEntry{
 			name: "floor",
 			arguments: []argSpec{
-				{types: []jpType{jpNumber}},
+				argSpec{types: []jpType{jpNumber}},
 			},
 			handler: jpfFloor,
 		},
-		"map": {
+		"map": functionEntry{
 			name: "amp",
 			arguments: []argSpec{
-				{types: []jpType{jpExpref}},
-				{types: []jpType{jpArray}},
+				argSpec{types: []jpType{jpExpref}},
+				argSpec{types: []jpType{jpArray}},
 			},
 			handler:   jpfMap,
 			hasExpRef: true,
 		},
-		"max": {
+		"max": functionEntry{
 			name: "max",
 			arguments: []argSpec{
-				{types: []jpType{jpArrayNumber, jpArrayString}},
+				argSpec{types: []jpType{jpArrayNumber, jpArrayString}},
 			},
 			handler: jpfMax,
 		},
-		"merge": {
+		"merge": functionEntry{
 			name: "merge",
 			arguments: []argSpec{
-				{types: []jpType{jpObject}, variadic: true},
+				argSpec{types: []jpType{jpObject}, variadic: true},
 			},
 			handler: jpfMerge,
 		},
-		"max_by": {
+		"max_by": functionEntry{
 			name: "max_by",
 			arguments: []argSpec{
-				{types: []jpType{jpArray}},
-				{types: []jpType{jpExpref}},
+				argSpec{types: []jpType{jpArray}},
+				argSpec{types: []jpType{jpExpref}},
 			},
 			handler:   jpfMaxBy,
 			hasExpRef: true,
 		},
-		"sum": {
+		"sum": functionEntry{
 			name: "sum",
 			arguments: []argSpec{
-				{types: []jpType{jpArrayNumber}},
+				argSpec{types: []jpType{jpArrayNumber}},
 			},
 			handler: jpfSum,
 		},
-		"min": {
+		"min": functionEntry{
 			name: "min",
 			arguments: []argSpec{
-				{types: []jpType{jpArrayNumber, jpArrayString}},
+				argSpec{types: []jpType{jpArrayNumber, jpArrayString}},
 			},
 			handler: jpfMin,
 		},
-		"min_by": {
+		"min_by": functionEntry{
 			name: "min_by",
 			arguments: []argSpec{
-				{types: []jpType{jpArray}},
-				{types: []jpType{jpExpref}},
+				argSpec{types: []jpType{jpArray}},
+				argSpec{types: []jpType{jpExpref}},
 			},
 			handler:   jpfMinBy,
 			hasExpRef: true,
 		},
-		"type": {
+		"type": functionEntry{
 			name: "type",
 			arguments: []argSpec{
-				{types: []jpType{jpAny}},
+				argSpec{types: []jpType{jpAny}},
 			},
 			handler: jpfType,
 		},
-		"keys": {
+		"keys": functionEntry{
 			name: "keys",
 			arguments: []argSpec{
-				{types: []jpType{jpObject}},
+				argSpec{types: []jpType{jpObject}},
 			},
 			handler: jpfKeys,
 		},
-		"values": {
+		"values": functionEntry{
 			name: "values",
 			arguments: []argSpec{
-				{types: []jpType{jpObject}},
+				argSpec{types: []jpType{jpObject}},
 			},
 			handler: jpfValues,
 		},
-		"sort": {
+		"sort": functionEntry{
 			name: "sort",
 			arguments: []argSpec{
-				{types: []jpType{jpArrayString, jpArrayNumber}},
+				argSpec{types: []jpType{jpArrayString, jpArrayNumber}},
 			},
 			handler: jpfSort,
 		},
-		"sort_by": {
+		"sort_by": functionEntry{
 			name: "sort_by",
 			arguments: []argSpec{
-				{types: []jpType{jpArray}},
-				{types: []jpType{jpExpref}},
+				argSpec{types: []jpType{jpArray}},
+				argSpec{types: []jpType{jpExpref}},
 			},
 			handler:   jpfSortBy,
 			hasExpRef: true,
 		},
-		"join": {
+		"join": functionEntry{
 			name: "join",
 			arguments: []argSpec{
-				{types: []jpType{jpString}},
-				{types: []jpType{jpArrayString}},
+				argSpec{types: []jpType{jpString}},
+				argSpec{types: []jpType{jpArrayString}},
 			},
 			handler: jpfJoin,
 		},
-		"reverse": {
+		"reverse": functionEntry{
 			name: "reverse",
 			arguments: []argSpec{
-				{types: []jpType{jpArray, jpString}},
+				argSpec{types: []jpType{jpArray, jpString}},
 			},
 			handler: jpfReverse,
 		},
-		"to_array": {
+		"to_array": functionEntry{
 			name: "to_array",
 			arguments: []argSpec{
-				{types: []jpType{jpAny}},
+				argSpec{types: []jpType{jpAny}},
 			},
 			handler: jpfToArray,
 		},
-		"to_string": {
+		"to_string": functionEntry{
 			name: "to_string",
 			arguments: []argSpec{
-				{types: []jpType{jpAny}},
+				argSpec{types: []jpType{jpAny}},
 			},
 			handler: jpfToString,
 		},
-		"to_number": {
+		"to_number": functionEntry{
 			name: "to_number",
 			arguments: []argSpec{
-				{types: []jpType{jpAny}},
+				argSpec{types: []jpType{jpAny}},
 			},
 			handler: jpfToNumber,
 		},
-		"not_null": {
+		"not_null": functionEntry{
 			name: "not_null",
 			arguments: []argSpec{
-				{types: []jpType{jpAny}, variadic: true},
+				argSpec{types: []jpType{jpAny}, variadic: true},
 			},
 			handler: jpfNotNull,
 		},
@@ -358,7 +357,7 @@ func (a *argSpec) typeCheck(arg interface{}) error {
 				return nil
 			}
 		case jpArray:
-			if isSliceType(arg) {
+			if _, ok := arg.([]interface{}); ok {
 				return nil
 			}
 		case jpObject:
@@ -410,9 +409,8 @@ func jpfLength(arguments []interface{}) (interface{}, error) {
 	arg := arguments[0]
 	if c, ok := arg.(string); ok {
 		return float64(utf8.RuneCountInString(c)), nil
-	} else if isSliceType(arg) {
-		v := reflect.ValueOf(arg)
-		return float64(v.Len()), nil
+	} else if c, ok := arg.([]interface{}); ok {
+		return float64(len(c)), nil
 	} else if c, ok := arg.(map[string]interface{}); ok {
 		return float64(len(c)), nil
 	}

+ 2 - 2
vendor/github.com/jmespath/go-jmespath/parser.go

@@ -353,7 +353,7 @@ func (p *Parser) nud(token token) (ASTNode, error) {
 	case tFlatten:
 		left := ASTNode{
 			nodeType: ASTFlatten,
-			children: []ASTNode{{nodeType: ASTIdentity}},
+			children: []ASTNode{ASTNode{nodeType: ASTIdentity}},
 		}
 		right, err := p.parseProjectionRHS(bindingPowers[tFlatten])
 		if err != nil {
@@ -378,7 +378,7 @@ func (p *Parser) nud(token token) (ASTNode, error) {
 			}
 			return ASTNode{
 				nodeType: ASTProjection,
-				children: []ASTNode{{nodeType: ASTIdentity}, right},
+				children: []ASTNode{ASTNode{nodeType: ASTIdentity}, right},
 			}, nil
 		} else {
 			return p.parseMultiSelectList()

+ 0 - 4
vendor/github.com/json-iterator/go/README.md

@@ -10,10 +10,6 @@ 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)
 
-```
-Go开发者们请加入我们,滴滴出行平台技术部 taowen@didichuxing.com
-```
-
 # Benchmark
 
 ![benchmark](http://jsoniter.com/benchmarks/go-benchmark.png)

+ 1 - 1
vendor/github.com/json-iterator/go/adapter.go

@@ -16,7 +16,7 @@ func Unmarshal(data []byte, v interface{}) error {
 	return ConfigDefault.Unmarshal(data, v)
 }
 
-// UnmarshalFromString convenient method to read from string instead of []byte
+// UnmarshalFromString is a convenient method to read from string instead of []byte
 func UnmarshalFromString(str string, v interface{}) error {
 	return ConfigDefault.UnmarshalFromString(str, v)
 }

+ 4 - 0
vendor/github.com/json-iterator/go/any.go

@@ -312,6 +312,10 @@ func (codec *directAnyCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
 
 func (codec *directAnyCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
 	any := *(*Any)(ptr)
+	if any == nil {
+		stream.WriteNil()
+		return
+	}
 	any.WriteTo(stream)
 }
 

+ 11 - 0
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
+)

+ 14 - 0
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=

+ 6 - 14
vendor/github.com/json-iterator/go/iter_float.go

@@ -77,14 +77,12 @@ func (iter *Iterator) ReadFloat32() (ret float32) {
 }
 
 func (iter *Iterator) readPositiveFloat32() (ret float32) {
-	value := uint64(0)
-	c := byte(' ')
 	i := iter.head
 	// first char
 	if i == iter.tail {
 		return iter.readFloat32SlowPath()
 	}
-	c = iter.buf[i]
+	c := iter.buf[i]
 	i++
 	ind := floatDigits[c]
 	switch ind {
@@ -107,7 +105,7 @@ func (iter *Iterator) readPositiveFloat32() (ret float32) {
 			return
 		}
 	}
-	value = uint64(ind)
+	value := uint64(ind)
 	// chars before dot
 non_decimal_loop:
 	for ; i < iter.tail; i++ {
@@ -145,9 +143,7 @@ non_decimal_loop:
 				}
 				// too many decimal places
 				return iter.readFloat32SlowPath()
-			case invalidCharForNumber:
-				fallthrough
-			case dotInNumber:
+			case invalidCharForNumber, dotInNumber:
 				return iter.readFloat32SlowPath()
 			}
 			decimalPlaces++
@@ -218,14 +214,12 @@ func (iter *Iterator) ReadFloat64() (ret float64) {
 }
 
 func (iter *Iterator) readPositiveFloat64() (ret float64) {
-	value := uint64(0)
-	c := byte(' ')
 	i := iter.head
 	// first char
 	if i == iter.tail {
 		return iter.readFloat64SlowPath()
 	}
-	c = iter.buf[i]
+	c := iter.buf[i]
 	i++
 	ind := floatDigits[c]
 	switch ind {
@@ -248,7 +242,7 @@ func (iter *Iterator) readPositiveFloat64() (ret float64) {
 			return
 		}
 	}
-	value = uint64(ind)
+	value := uint64(ind)
 	// chars before dot
 non_decimal_loop:
 	for ; i < iter.tail; i++ {
@@ -286,9 +280,7 @@ non_decimal_loop:
 				}
 				// too many decimal places
 				return iter.readFloat64SlowPath()
-			case invalidCharForNumber:
-				fallthrough
-			case dotInNumber:
+			case invalidCharForNumber, dotInNumber:
 				return iter.readFloat64SlowPath()
 			}
 			decimalPlaces++

+ 13 - 12
vendor/github.com/json-iterator/go/iter_skip.go

@@ -37,17 +37,24 @@ func (iter *Iterator) SkipAndReturnBytes() []byte {
 	return iter.stopCapture()
 }
 
-type captureBuffer struct {
-	startedAt int
-	captured  []byte
+// 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) startCapture(captureStartedAt int) {
+func (iter *Iterator) startCaptureTo(buf []byte, captureStartedAt int) {
 	if iter.captured != nil {
 		panic("already in capture mode")
 	}
 	iter.captureStartedAt = captureStartedAt
-	iter.captured = make([]byte, 0, 32)
+	iter.captured = buf
+}
+
+func (iter *Iterator) startCapture(captureStartedAt int) {
+	iter.startCaptureTo(make([]byte, 0, 32), captureStartedAt)
 }
 
 func (iter *Iterator) stopCapture() []byte {
@@ -58,13 +65,7 @@ func (iter *Iterator) stopCapture() []byte {
 	remaining := iter.buf[iter.captureStartedAt:iter.head]
 	iter.captureStartedAt = -1
 	iter.captured = nil
-	if len(captured) == 0 {
-		copied := make([]byte, len(remaining))
-		copy(copied, remaining)
-		return copied
-	}
-	captured = append(captured, remaining...)
-	return captured
+	return append(captured, remaining...)
 }
 
 // Skip skips a json object and positions to relatively the next json object

+ 12 - 2
vendor/github.com/json-iterator/go/iter_skip_strict.go

@@ -2,12 +2,22 @@
 
 package jsoniter
 
-import "fmt"
+import (
+	"fmt"
+	"io"
+)
 
 func (iter *Iterator) skipNumber() {
 	if !iter.trySkipNumber() {
 		iter.unreadByte()
-		iter.ReadFloat32()
+		if iter.Error != nil && iter.Error != io.EOF {
+			return
+		}
+		iter.ReadFloat64()
+		if iter.Error != nil && iter.Error != io.EOF {
+			iter.Error = nil
+			iter.ReadBigFloat()
+		}
 	}
 }
 

+ 1 - 1
vendor/github.com/json-iterator/go/reflect_extension.go

@@ -338,7 +338,7 @@ func describeStruct(ctx *ctx, typ reflect2.Type) *StructDescriptor {
 	for i := 0; i < structType.NumField(); i++ {
 		field := structType.Field(i)
 		tag, hastag := field.Tag().Lookup(ctx.getTagKey())
-		if ctx.onlyTaggedField && !hastag {
+		if ctx.onlyTaggedField && !hastag && !field.Anonymous() {
 			continue
 		}
 		tagParts := strings.Split(tag, ",")

+ 14 - 2
vendor/github.com/json-iterator/go/reflect_map.go

@@ -64,14 +64,26 @@ func decoderOfMapKey(ctx *ctx, typ reflect2.Type) ValDecoder {
 		return &numericMapKeyDecoder{decoderOfType(ctx, typ)}
 	default:
 		ptrType := reflect2.PtrTo(typ)
-		if ptrType.Implements(textMarshalerType) {
+		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(textMarshalerType) {
+		if typ.Implements(textUnmarshalerType) {
 			return &textUnmarshalerDecoder{
 				valType: typ,
 			}

+ 1 - 2
vendor/github.com/json-iterator/go/reflect_marshaler.go

@@ -93,8 +93,7 @@ func (encoder *marshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
 		stream.WriteNil()
 		return
 	}
-	marshaler := obj.(json.Marshaler)
-	bytes, err := marshaler.MarshalJSON()
+	bytes, err := json.Marshal(obj)
 	if err != nil {
 		stream.Error = err
 	} else {

+ 8 - 6
vendor/github.com/json-iterator/go/reflect_native.go

@@ -432,17 +432,19 @@ func (codec *base64Codec) Decode(ptr unsafe.Pointer, iter *Iterator) {
 }
 
 func (codec *base64Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
-	src := *((*[]byte)(ptr))
-	if len(src) == 0 {
+	if codec.sliceType.UnsafeIsNil(ptr) {
 		stream.WriteNil()
 		return
 	}
+	src := *((*[]byte)(ptr))
 	encoding := base64.StdEncoding
 	stream.writeByte('"')
-	size := encoding.EncodedLen(len(src))
-	buf := make([]byte, size)
-	encoding.Encode(buf, src)
-	stream.buf = append(stream.buf, buf...)
+	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('"')
 }
 

+ 1 - 1
vendor/github.com/json-iterator/go/reflect_struct_decoder.go

@@ -530,8 +530,8 @@ func (decoder *generalStructDecoder) decodeOneField(ptr unsafe.Pointer, iter *It
 		}
 	}
 	if fieldDecoder == nil {
-		msg := "found unknown field: " + field
 		if decoder.disallowUnknownFields {
+			msg := "found unknown field: " + field
 			iter.ReportError("ReadObject", msg)
 		}
 		c := iter.nextToken()

+ 17 - 0
vendor/github.com/json-iterator/go/stream_float.go

@@ -1,6 +1,7 @@
 package jsoniter
 
 import (
+	"fmt"
 	"math"
 	"strconv"
 )
@@ -13,6 +14,10 @@ func init() {
 
 // 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.
@@ -26,6 +31,10 @@ func (stream *Stream) WriteFloat32(val float32) {
 
 // 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
@@ -54,6 +63,10 @@ func (stream *Stream) WriteFloat32Lossy(val float32) {
 
 // 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.
@@ -67,6 +80,10 @@ func (stream *Stream) WriteFloat64(val float64) {
 
 // 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

+ 0 - 23
vendor/github.com/satori/go.uuid/.travis.yml

@@ -1,23 +0,0 @@
-language: go
-sudo: false
-go:
-    - 1.2
-    - 1.3
-    - 1.4
-    - 1.5
-    - 1.6
-    - 1.7
-    - 1.8
-    - 1.9
-    - tip
-matrix:
-    allow_failures:
-        - go: tip
-    fast_finish: true
-before_install:
-    - go get github.com/mattn/goveralls
-    - go get golang.org/x/tools/cmd/cover
-script:
-    - $HOME/gopath/bin/goveralls -service=travis-ci
-notifications:
-    email: false

+ 0 - 20
vendor/github.com/satori/go.uuid/LICENSE

@@ -1,20 +0,0 @@
-Copyright (C) 2013-2018 by Maxim Bublis <b@codemonkey.ru>
-
-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.

+ 0 - 65
vendor/github.com/satori/go.uuid/README.md

@@ -1,65 +0,0 @@
-# UUID package for Go language
-
-[![Build Status](https://travis-ci.org/satori/go.uuid.png?branch=master)](https://travis-ci.org/satori/go.uuid)
-[![Coverage Status](https://coveralls.io/repos/github/satori/go.uuid/badge.svg?branch=master)](https://coveralls.io/github/satori/go.uuid)
-[![GoDoc](http://godoc.org/github.com/satori/go.uuid?status.png)](http://godoc.org/github.com/satori/go.uuid)
-
-This package provides pure Go implementation of Universally Unique Identifier (UUID). Supported both creation and parsing of UUIDs.
-
-With 100% test coverage and benchmarks out of box.
-
-Supported versions:
-* Version 1, based on timestamp and MAC address (RFC 4122)
-* Version 2, based on timestamp, MAC address and POSIX UID/GID (DCE 1.1)
-* Version 3, based on MD5 hashing (RFC 4122)
-* Version 4, based on random numbers (RFC 4122)
-* Version 5, based on SHA-1 hashing (RFC 4122)
-
-## Installation
-
-Use the `go` command:
-
-	$ go get github.com/satori/go.uuid
-
-## Requirements
-
-UUID package requires Go >= 1.2.
-
-## Example
-
-```go
-package main
-
-import (
-	"fmt"
-	"github.com/satori/go.uuid"
-)
-
-func main() {
-	// Creating UUID Version 4
-	u1 := uuid.NewV4()
-	fmt.Printf("UUIDv4: %s\n", u1)
-
-	// Parsing UUID from string input
-	u2, err := uuid.FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
-	if err != nil {
-		fmt.Printf("Something gone wrong: %s", err)
-	}
-	fmt.Printf("Successfully parsed: %s", u2)
-}
-```
-
-## Documentation
-
-[Documentation](http://godoc.org/github.com/satori/go.uuid) is hosted at GoDoc project.
-
-## Links
-* [RFC 4122](http://tools.ietf.org/html/rfc4122)
-* [DCE 1.1: Authentication and Security Services](http://pubs.opengroup.org/onlinepubs/9696989899/chap5.htm#tagcjh_08_02_01_01)
-
-## Copyright
-
-Copyright (C) 2013-2018 by Maxim Bublis <b@codemonkey.ru>.
-
-UUID package released under MIT License.
-See [LICENSE](https://github.com/satori/go.uuid/blob/master/LICENSE) for details.

+ 0 - 206
vendor/github.com/satori/go.uuid/codec.go

@@ -1,206 +0,0 @@
-// Copyright (C) 2013-2018 by Maxim Bublis <b@codemonkey.ru>
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-package uuid
-
-import (
-	"bytes"
-	"encoding/hex"
-	"fmt"
-)
-
-// FromBytes returns UUID converted from raw byte slice input.
-// It will return error if the slice isn't 16 bytes long.
-func FromBytes(input []byte) (u UUID, err error) {
-	err = u.UnmarshalBinary(input)
-	return
-}
-
-// FromBytesOrNil returns UUID converted from raw byte slice input.
-// Same behavior as FromBytes, but returns a Nil UUID on error.
-func FromBytesOrNil(input []byte) UUID {
-	uuid, err := FromBytes(input)
-	if err != nil {
-		return Nil
-	}
-	return uuid
-}
-
-// FromString returns UUID parsed from string input.
-// Input is expected in a form accepted by UnmarshalText.
-func FromString(input string) (u UUID, err error) {
-	err = u.UnmarshalText([]byte(input))
-	return
-}
-
-// FromStringOrNil returns UUID parsed from string input.
-// Same behavior as FromString, but returns a Nil UUID on error.
-func FromStringOrNil(input string) UUID {
-	uuid, err := FromString(input)
-	if err != nil {
-		return Nil
-	}
-	return uuid
-}
-
-// MarshalText implements the encoding.TextMarshaler interface.
-// The encoding is the same as returned by String.
-func (u UUID) MarshalText() (text []byte, err error) {
-	text = []byte(u.String())
-	return
-}
-
-// UnmarshalText implements the encoding.TextUnmarshaler interface.
-// Following formats are supported:
-//   "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
-//   "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}",
-//   "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8"
-//   "6ba7b8109dad11d180b400c04fd430c8"
-// ABNF for supported UUID text representation follows:
-//   uuid := canonical | hashlike | braced | urn
-//   plain := canonical | hashlike
-//   canonical := 4hexoct '-' 2hexoct '-' 2hexoct '-' 6hexoct
-//   hashlike := 12hexoct
-//   braced := '{' plain '}'
-//   urn := URN ':' UUID-NID ':' plain
-//   URN := 'urn'
-//   UUID-NID := 'uuid'
-//   12hexoct := 6hexoct 6hexoct
-//   6hexoct := 4hexoct 2hexoct
-//   4hexoct := 2hexoct 2hexoct
-//   2hexoct := hexoct hexoct
-//   hexoct := hexdig hexdig
-//   hexdig := '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' |
-//             'a' | 'b' | 'c' | 'd' | 'e' | 'f' |
-//             'A' | 'B' | 'C' | 'D' | 'E' | 'F'
-func (u *UUID) UnmarshalText(text []byte) (err error) {
-	switch len(text) {
-	case 32:
-		return u.decodeHashLike(text)
-	case 36:
-		return u.decodeCanonical(text)
-	case 38:
-		return u.decodeBraced(text)
-	case 41:
-		fallthrough
-	case 45:
-		return u.decodeURN(text)
-	default:
-		return fmt.Errorf("uuid: incorrect UUID length: %s", text)
-	}
-}
-
-// decodeCanonical decodes UUID string in format
-// "6ba7b810-9dad-11d1-80b4-00c04fd430c8".
-func (u *UUID) decodeCanonical(t []byte) (err error) {
-	if t[8] != '-' || t[13] != '-' || t[18] != '-' || t[23] != '-' {
-		return fmt.Errorf("uuid: incorrect UUID format %s", t)
-	}
-
-	src := t[:]
-	dst := u[:]
-
-	for i, byteGroup := range byteGroups {
-		if i > 0 {
-			src = src[1:] // skip dash
-		}
-		_, err = hex.Decode(dst[:byteGroup/2], src[:byteGroup])
-		if err != nil {
-			return
-		}
-		src = src[byteGroup:]
-		dst = dst[byteGroup/2:]
-	}
-
-	return
-}
-
-// decodeHashLike decodes UUID string in format
-// "6ba7b8109dad11d180b400c04fd430c8".
-func (u *UUID) decodeHashLike(t []byte) (err error) {
-	src := t[:]
-	dst := u[:]
-
-	if _, err = hex.Decode(dst, src); err != nil {
-		return err
-	}
-	return
-}
-
-// decodeBraced decodes UUID string in format
-// "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}" or in format
-// "{6ba7b8109dad11d180b400c04fd430c8}".
-func (u *UUID) decodeBraced(t []byte) (err error) {
-	l := len(t)
-
-	if t[0] != '{' || t[l-1] != '}' {
-		return fmt.Errorf("uuid: incorrect UUID format %s", t)
-	}
-
-	return u.decodePlain(t[1 : l-1])
-}
-
-// decodeURN decodes UUID string in format
-// "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8" or in format
-// "urn:uuid:6ba7b8109dad11d180b400c04fd430c8".
-func (u *UUID) decodeURN(t []byte) (err error) {
-	total := len(t)
-
-	urn_uuid_prefix := t[:9]
-
-	if !bytes.Equal(urn_uuid_prefix, urnPrefix) {
-		return fmt.Errorf("uuid: incorrect UUID format: %s", t)
-	}
-
-	return u.decodePlain(t[9:total])
-}
-
-// decodePlain decodes UUID string in canonical format
-// "6ba7b810-9dad-11d1-80b4-00c04fd430c8" or in hash-like format
-// "6ba7b8109dad11d180b400c04fd430c8".
-func (u *UUID) decodePlain(t []byte) (err error) {
-	switch len(t) {
-	case 32:
-		return u.decodeHashLike(t)
-	case 36:
-		return u.decodeCanonical(t)
-	default:
-		return fmt.Errorf("uuid: incorrrect UUID length: %s", t)
-	}
-}
-
-// MarshalBinary implements the encoding.BinaryMarshaler interface.
-func (u UUID) MarshalBinary() (data []byte, err error) {
-	data = u.Bytes()
-	return
-}
-
-// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.
-// It will return error if the slice isn't 16 bytes long.
-func (u *UUID) UnmarshalBinary(data []byte) (err error) {
-	if len(data) != Size {
-		err = fmt.Errorf("uuid: UUID must be exactly 16 bytes long, got %d bytes", len(data))
-		return
-	}
-	copy(u[:], data)
-
-	return
-}

+ 0 - 239
vendor/github.com/satori/go.uuid/generator.go

@@ -1,239 +0,0 @@
-// Copyright (C) 2013-2018 by Maxim Bublis <b@codemonkey.ru>
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-package uuid
-
-import (
-	"crypto/md5"
-	"crypto/rand"
-	"crypto/sha1"
-	"encoding/binary"
-	"hash"
-	"net"
-	"os"
-	"sync"
-	"time"
-)
-
-// Difference in 100-nanosecond intervals between
-// UUID epoch (October 15, 1582) and Unix epoch (January 1, 1970).
-const epochStart = 122192928000000000
-
-var (
-	global = newDefaultGenerator()
-
-	epochFunc = unixTimeFunc
-	posixUID  = uint32(os.Getuid())
-	posixGID  = uint32(os.Getgid())
-)
-
-// NewV1 returns UUID based on current timestamp and MAC address.
-func NewV1() UUID {
-	return global.NewV1()
-}
-
-// NewV2 returns DCE Security UUID based on POSIX UID/GID.
-func NewV2(domain byte) UUID {
-	return global.NewV2(domain)
-}
-
-// NewV3 returns UUID based on MD5 hash of namespace UUID and name.
-func NewV3(ns UUID, name string) UUID {
-	return global.NewV3(ns, name)
-}
-
-// NewV4 returns random generated UUID.
-func NewV4() UUID {
-	return global.NewV4()
-}
-
-// NewV5 returns UUID based on SHA-1 hash of namespace UUID and name.
-func NewV5(ns UUID, name string) UUID {
-	return global.NewV5(ns, name)
-}
-
-// Generator provides interface for generating UUIDs.
-type Generator interface {
-	NewV1() UUID
-	NewV2(domain byte) UUID
-	NewV3(ns UUID, name string) UUID
-	NewV4() UUID
-	NewV5(ns UUID, name string) UUID
-}
-
-// Default generator implementation.
-type generator struct {
-	storageOnce  sync.Once
-	storageMutex sync.Mutex
-
-	lastTime      uint64
-	clockSequence uint16
-	hardwareAddr  [6]byte
-}
-
-func newDefaultGenerator() Generator {
-	return &generator{}
-}
-
-// NewV1 returns UUID based on current timestamp and MAC address.
-func (g *generator) NewV1() UUID {
-	u := UUID{}
-
-	timeNow, clockSeq, hardwareAddr := g.getStorage()
-
-	binary.BigEndian.PutUint32(u[0:], uint32(timeNow))
-	binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32))
-	binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48))
-	binary.BigEndian.PutUint16(u[8:], clockSeq)
-
-	copy(u[10:], hardwareAddr)
-
-	u.SetVersion(V1)
-	u.SetVariant(VariantRFC4122)
-
-	return u
-}
-
-// NewV2 returns DCE Security UUID based on POSIX UID/GID.
-func (g *generator) NewV2(domain byte) UUID {
-	u := UUID{}
-
-	timeNow, clockSeq, hardwareAddr := g.getStorage()
-
-	switch domain {
-	case DomainPerson:
-		binary.BigEndian.PutUint32(u[0:], posixUID)
-	case DomainGroup:
-		binary.BigEndian.PutUint32(u[0:], posixGID)
-	}
-
-	binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32))
-	binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48))
-	binary.BigEndian.PutUint16(u[8:], clockSeq)
-	u[9] = domain
-
-	copy(u[10:], hardwareAddr)
-
-	u.SetVersion(V2)
-	u.SetVariant(VariantRFC4122)
-
-	return u
-}
-
-// NewV3 returns UUID based on MD5 hash of namespace UUID and name.
-func (g *generator) NewV3(ns UUID, name string) UUID {
-	u := newFromHash(md5.New(), ns, name)
-	u.SetVersion(V3)
-	u.SetVariant(VariantRFC4122)
-
-	return u
-}
-
-// NewV4 returns random generated UUID.
-func (g *generator) NewV4() UUID {
-	u := UUID{}
-	g.safeRandom(u[:])
-	u.SetVersion(V4)
-	u.SetVariant(VariantRFC4122)
-
-	return u
-}
-
-// NewV5 returns UUID based on SHA-1 hash of namespace UUID and name.
-func (g *generator) NewV5(ns UUID, name string) UUID {
-	u := newFromHash(sha1.New(), ns, name)
-	u.SetVersion(V5)
-	u.SetVariant(VariantRFC4122)
-
-	return u
-}
-
-func (g *generator) initStorage() {
-	g.initClockSequence()
-	g.initHardwareAddr()
-}
-
-func (g *generator) initClockSequence() {
-	buf := make([]byte, 2)
-	g.safeRandom(buf)
-	g.clockSequence = binary.BigEndian.Uint16(buf)
-}
-
-func (g *generator) initHardwareAddr() {
-	interfaces, err := net.Interfaces()
-	if err == nil {
-		for _, iface := range interfaces {
-			if len(iface.HardwareAddr) >= 6 {
-				copy(g.hardwareAddr[:], iface.HardwareAddr)
-				return
-			}
-		}
-	}
-
-	// Initialize hardwareAddr randomly in case
-	// of real network interfaces absence
-	g.safeRandom(g.hardwareAddr[:])
-
-	// Set multicast bit as recommended in RFC 4122
-	g.hardwareAddr[0] |= 0x01
-}
-
-func (g *generator) safeRandom(dest []byte) {
-	if _, err := rand.Read(dest); err != nil {
-		panic(err)
-	}
-}
-
-// Returns UUID v1/v2 storage state.
-// Returns epoch timestamp, clock sequence, and hardware address.
-func (g *generator) getStorage() (uint64, uint16, []byte) {
-	g.storageOnce.Do(g.initStorage)
-
-	g.storageMutex.Lock()
-	defer g.storageMutex.Unlock()
-
-	timeNow := epochFunc()
-	// Clock changed backwards since last UUID generation.
-	// Should increase clock sequence.
-	if timeNow <= g.lastTime {
-		g.clockSequence++
-	}
-	g.lastTime = timeNow
-
-	return timeNow, g.clockSequence, g.hardwareAddr[:]
-}
-
-// Returns difference in 100-nanosecond intervals between
-// UUID epoch (October 15, 1582) and current time.
-// This is default epoch calculation function.
-func unixTimeFunc() uint64 {
-	return epochStart + uint64(time.Now().UnixNano()/100)
-}
-
-// Returns UUID based on hashing of namespace UUID and name.
-func newFromHash(h hash.Hash, ns UUID, name string) UUID {
-	u := UUID{}
-	h.Write(ns[:])
-	h.Write([]byte(name))
-	copy(u[:], h.Sum(nil))
-
-	return u
-}

+ 0 - 78
vendor/github.com/satori/go.uuid/sql.go

@@ -1,78 +0,0 @@
-// Copyright (C) 2013-2018 by Maxim Bublis <b@codemonkey.ru>
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-package uuid
-
-import (
-	"database/sql/driver"
-	"fmt"
-)
-
-// Value implements the driver.Valuer interface.
-func (u UUID) Value() (driver.Value, error) {
-	return u.String(), nil
-}
-
-// Scan implements the sql.Scanner interface.
-// A 16-byte slice is handled by UnmarshalBinary, while
-// a longer byte slice or a string is handled by UnmarshalText.
-func (u *UUID) Scan(src interface{}) error {
-	switch src := src.(type) {
-	case []byte:
-		if len(src) == Size {
-			return u.UnmarshalBinary(src)
-		}
-		return u.UnmarshalText(src)
-
-	case string:
-		return u.UnmarshalText([]byte(src))
-	}
-
-	return fmt.Errorf("uuid: cannot convert %T to UUID", src)
-}
-
-// NullUUID can be used with the standard sql package to represent a
-// UUID value that can be NULL in the database
-type NullUUID struct {
-	UUID  UUID
-	Valid bool
-}
-
-// Value implements the driver.Valuer interface.
-func (u NullUUID) Value() (driver.Value, error) {
-	if !u.Valid {
-		return nil, nil
-	}
-	// Delegate to UUID Value function
-	return u.UUID.Value()
-}
-
-// Scan implements the sql.Scanner interface.
-func (u *NullUUID) Scan(src interface{}) error {
-	if src == nil {
-		u.UUID, u.Valid = Nil, false
-		return nil
-	}
-
-	// Delegate to UUID Scan function
-	u.Valid = true
-	return u.UUID.Scan(src)
-}

+ 0 - 161
vendor/github.com/satori/go.uuid/uuid.go

@@ -1,161 +0,0 @@
-// Copyright (C) 2013-2018 by Maxim Bublis <b@codemonkey.ru>
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-// Package uuid provides implementation of Universally Unique Identifier (UUID).
-// Supported versions are 1, 3, 4 and 5 (as specified in RFC 4122) and
-// version 2 (as specified in DCE 1.1).
-package uuid
-
-import (
-	"bytes"
-	"encoding/hex"
-)
-
-// Size of a UUID in bytes.
-const Size = 16
-
-// UUID representation compliant with specification
-// described in RFC 4122.
-type UUID [Size]byte
-
-// UUID versions
-const (
-	_ byte = iota
-	V1
-	V2
-	V3
-	V4
-	V5
-)
-
-// UUID layout variants.
-const (
-	VariantNCS byte = iota
-	VariantRFC4122
-	VariantMicrosoft
-	VariantFuture
-)
-
-// UUID DCE domains.
-const (
-	DomainPerson = iota
-	DomainGroup
-	DomainOrg
-)
-
-// String parse helpers.
-var (
-	urnPrefix  = []byte("urn:uuid:")
-	byteGroups = []int{8, 4, 4, 4, 12}
-)
-
-// Nil is special form of UUID that is specified to have all
-// 128 bits set to zero.
-var Nil = UUID{}
-
-// Predefined namespace UUIDs.
-var (
-	NamespaceDNS  = Must(FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8"))
-	NamespaceURL  = Must(FromString("6ba7b811-9dad-11d1-80b4-00c04fd430c8"))
-	NamespaceOID  = Must(FromString("6ba7b812-9dad-11d1-80b4-00c04fd430c8"))
-	NamespaceX500 = Must(FromString("6ba7b814-9dad-11d1-80b4-00c04fd430c8"))
-)
-
-// Equal returns true if u1 and u2 equals, otherwise returns false.
-func Equal(u1 UUID, u2 UUID) bool {
-	return bytes.Equal(u1[:], u2[:])
-}
-
-// Version returns algorithm version used to generate UUID.
-func (u UUID) Version() byte {
-	return u[6] >> 4
-}
-
-// Variant returns UUID layout variant.
-func (u UUID) Variant() byte {
-	switch {
-	case (u[8] >> 7) == 0x00:
-		return VariantNCS
-	case (u[8] >> 6) == 0x02:
-		return VariantRFC4122
-	case (u[8] >> 5) == 0x06:
-		return VariantMicrosoft
-	case (u[8] >> 5) == 0x07:
-		fallthrough
-	default:
-		return VariantFuture
-	}
-}
-
-// Bytes returns bytes slice representation of UUID.
-func (u UUID) Bytes() []byte {
-	return u[:]
-}
-
-// Returns canonical string representation of UUID:
-// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
-func (u UUID) String() string {
-	buf := make([]byte, 36)
-
-	hex.Encode(buf[0:8], u[0:4])
-	buf[8] = '-'
-	hex.Encode(buf[9:13], u[4:6])
-	buf[13] = '-'
-	hex.Encode(buf[14:18], u[6:8])
-	buf[18] = '-'
-	hex.Encode(buf[19:23], u[8:10])
-	buf[23] = '-'
-	hex.Encode(buf[24:], u[10:])
-
-	return string(buf)
-}
-
-// SetVersion sets version bits.
-func (u *UUID) SetVersion(v byte) {
-	u[6] = (u[6] & 0x0f) | (v << 4)
-}
-
-// SetVariant sets variant bits.
-func (u *UUID) SetVariant(v byte) {
-	switch v {
-	case VariantNCS:
-		u[8] = (u[8]&(0xff>>1) | (0x00 << 7))
-	case VariantRFC4122:
-		u[8] = (u[8]&(0xff>>2) | (0x02 << 6))
-	case VariantMicrosoft:
-		u[8] = (u[8]&(0xff>>3) | (0x06 << 5))
-	case VariantFuture:
-		fallthrough
-	default:
-		u[8] = (u[8]&(0xff>>3) | (0x07 << 5))
-	}
-}
-
-// Must is a helper that wraps a call to a function returning (UUID, error)
-// and panics if the error is non-nil. It is intended for use in variable
-// initializations such as
-//	var packageUUID = uuid.Must(uuid.FromString("123e4567-e89b-12d3-a456-426655440000"));
-func Must(u UUID, err error) UUID {
-	if err != nil {
-		panic(err)
-	}
-	return u
-}

+ 82 - 0
vendor/github.com/stretchr/testify/assert/assertion_format.go

@@ -113,6 +113,17 @@ func Errorf(t TestingT, err error, msg string, args ...interface{}) bool {
 	return Error(t, err, append([]interface{}{msg}, args...)...)
 }
 
+// Eventuallyf asserts that given condition will be met in waitFor time,
+// periodically checking target function each tick.
+//
+//    assert.Eventuallyf(t, func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
+func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return Eventually(t, condition, waitFor, tick, append([]interface{}{msg}, args...)...)
+}
+
 // Exactlyf asserts that two objects are equal in value and type.
 //
 //    assert.Exactlyf(t, int32(123, "error message %s", "formatted"), int64(123))
@@ -157,6 +168,31 @@ func FileExistsf(t TestingT, path string, msg string, args ...interface{}) bool
 	return FileExists(t, path, append([]interface{}{msg}, args...)...)
 }
 
+// Greaterf asserts that the first element is greater than the second
+//
+//    assert.Greaterf(t, 2, 1, "error message %s", "formatted")
+//    assert.Greaterf(t, float64(2, "error message %s", "formatted"), float64(1))
+//    assert.Greaterf(t, "b", "a", "error message %s", "formatted")
+func Greaterf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return Greater(t, e1, e2, append([]interface{}{msg}, args...)...)
+}
+
+// GreaterOrEqualf asserts that the first element is greater than or equal to the second
+//
+//    assert.GreaterOrEqualf(t, 2, 1, "error message %s", "formatted")
+//    assert.GreaterOrEqualf(t, 2, 2, "error message %s", "formatted")
+//    assert.GreaterOrEqualf(t, "b", "a", "error message %s", "formatted")
+//    assert.GreaterOrEqualf(t, "b", "b", "error message %s", "formatted")
+func GreaterOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return GreaterOrEqual(t, e1, e2, append([]interface{}{msg}, args...)...)
+}
+
 // HTTPBodyContainsf asserts that a specified handler returns a
 // body that contains a string.
 //
@@ -289,6 +325,14 @@ func JSONEqf(t TestingT, expected string, actual string, msg string, args ...int
 	return JSONEq(t, expected, actual, append([]interface{}{msg}, args...)...)
 }
 
+// YAMLEqf asserts that two YAML strings are equivalent.
+func YAMLEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return YAMLEq(t, expected, actual, append([]interface{}{msg}, args...)...)
+}
+
 // Lenf asserts that the specified object has specific length.
 // Lenf also fails if the object has a type that len() not accept.
 //
@@ -300,6 +344,31 @@ func Lenf(t TestingT, object interface{}, length int, msg string, args ...interf
 	return Len(t, object, length, append([]interface{}{msg}, args...)...)
 }
 
+// Lessf asserts that the first element is less than the second
+//
+//    assert.Lessf(t, 1, 2, "error message %s", "formatted")
+//    assert.Lessf(t, float64(1, "error message %s", "formatted"), float64(2))
+//    assert.Lessf(t, "a", "b", "error message %s", "formatted")
+func Lessf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return Less(t, e1, e2, append([]interface{}{msg}, args...)...)
+}
+
+// LessOrEqualf asserts that the first element is less than or equal to the second
+//
+//    assert.LessOrEqualf(t, 1, 2, "error message %s", "formatted")
+//    assert.LessOrEqualf(t, 2, 2, "error message %s", "formatted")
+//    assert.LessOrEqualf(t, "a", "b", "error message %s", "formatted")
+//    assert.LessOrEqualf(t, "b", "b", "error message %s", "formatted")
+func LessOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return LessOrEqual(t, e1, e2, append([]interface{}{msg}, args...)...)
+}
+
 // Nilf asserts that the specified object is nil.
 //
 //    assert.Nilf(t, err, "error message %s", "formatted")
@@ -444,6 +513,19 @@ func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...in
 	return Regexp(t, rx, str, append([]interface{}{msg}, args...)...)
 }
 
+// Samef asserts that two pointers reference the same object.
+//
+//    assert.Samef(t, ptr1, ptr2, "error message %s", "formatted")
+//
+// Both arguments must be pointer variables. Pointer variable sameness is
+// determined based on the equality of both type and value.
+func Samef(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return Same(t, expected, actual, append([]interface{}{msg}, args...)...)
+}
+
 // Subsetf asserts that the specified list(array, slice...) contains all
 // elements given in the specified subset(array, slice...).
 //

+ 164 - 0
vendor/github.com/stretchr/testify/assert/assertion_forward.go

@@ -215,6 +215,28 @@ func (a *Assertions) Errorf(err error, msg string, args ...interface{}) bool {
 	return Errorf(a.t, err, msg, args...)
 }
 
+// Eventually asserts that given condition will be met in waitFor time,
+// periodically checking target function each tick.
+//
+//    a.Eventually(func() bool { return true; }, time.Second, 10*time.Millisecond)
+func (a *Assertions) Eventually(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Eventually(a.t, condition, waitFor, tick, msgAndArgs...)
+}
+
+// Eventuallyf asserts that given condition will be met in waitFor time,
+// periodically checking target function each tick.
+//
+//    a.Eventuallyf(func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
+func (a *Assertions) Eventuallyf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Eventuallyf(a.t, condition, waitFor, tick, msg, args...)
+}
+
 // Exactly asserts that two objects are equal in value and type.
 //
 //    a.Exactly(int32(123), int64(123))
@@ -303,6 +325,56 @@ func (a *Assertions) FileExistsf(path string, msg string, args ...interface{}) b
 	return FileExistsf(a.t, path, msg, args...)
 }
 
+// Greater asserts that the first element is greater than the second
+//
+//    a.Greater(2, 1)
+//    a.Greater(float64(2), float64(1))
+//    a.Greater("b", "a")
+func (a *Assertions) Greater(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Greater(a.t, e1, e2, msgAndArgs...)
+}
+
+// GreaterOrEqual asserts that the first element is greater than or equal to the second
+//
+//    a.GreaterOrEqual(2, 1)
+//    a.GreaterOrEqual(2, 2)
+//    a.GreaterOrEqual("b", "a")
+//    a.GreaterOrEqual("b", "b")
+func (a *Assertions) GreaterOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return GreaterOrEqual(a.t, e1, e2, msgAndArgs...)
+}
+
+// GreaterOrEqualf asserts that the first element is greater than or equal to the second
+//
+//    a.GreaterOrEqualf(2, 1, "error message %s", "formatted")
+//    a.GreaterOrEqualf(2, 2, "error message %s", "formatted")
+//    a.GreaterOrEqualf("b", "a", "error message %s", "formatted")
+//    a.GreaterOrEqualf("b", "b", "error message %s", "formatted")
+func (a *Assertions) GreaterOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return GreaterOrEqualf(a.t, e1, e2, msg, args...)
+}
+
+// Greaterf asserts that the first element is greater than the second
+//
+//    a.Greaterf(2, 1, "error message %s", "formatted")
+//    a.Greaterf(float64(2, "error message %s", "formatted"), float64(1))
+//    a.Greaterf("b", "a", "error message %s", "formatted")
+func (a *Assertions) Greaterf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Greaterf(a.t, e1, e2, msg, args...)
+}
+
 // HTTPBodyContains asserts that a specified handler returns a
 // body that contains a string.
 //
@@ -567,6 +639,22 @@ func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ..
 	return JSONEqf(a.t, expected, actual, msg, args...)
 }
 
+// YAMLEq asserts that two YAML strings are equivalent.
+func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return YAMLEq(a.t, expected, actual, msgAndArgs...)
+}
+
+// YAMLEqf asserts that two YAML strings are equivalent.
+func (a *Assertions) YAMLEqf(expected string, actual string, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return YAMLEqf(a.t, expected, actual, msg, args...)
+}
+
 // Len asserts that the specified object has specific length.
 // Len also fails if the object has a type that len() not accept.
 //
@@ -589,6 +677,56 @@ func (a *Assertions) Lenf(object interface{}, length int, msg string, args ...in
 	return Lenf(a.t, object, length, msg, args...)
 }
 
+// Less asserts that the first element is less than the second
+//
+//    a.Less(1, 2)
+//    a.Less(float64(1), float64(2))
+//    a.Less("a", "b")
+func (a *Assertions) Less(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Less(a.t, e1, e2, msgAndArgs...)
+}
+
+// LessOrEqual asserts that the first element is less than or equal to the second
+//
+//    a.LessOrEqual(1, 2)
+//    a.LessOrEqual(2, 2)
+//    a.LessOrEqual("a", "b")
+//    a.LessOrEqual("b", "b")
+func (a *Assertions) LessOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return LessOrEqual(a.t, e1, e2, msgAndArgs...)
+}
+
+// LessOrEqualf asserts that the first element is less than or equal to the second
+//
+//    a.LessOrEqualf(1, 2, "error message %s", "formatted")
+//    a.LessOrEqualf(2, 2, "error message %s", "formatted")
+//    a.LessOrEqualf("a", "b", "error message %s", "formatted")
+//    a.LessOrEqualf("b", "b", "error message %s", "formatted")
+func (a *Assertions) LessOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return LessOrEqualf(a.t, e1, e2, msg, args...)
+}
+
+// Lessf asserts that the first element is less than the second
+//
+//    a.Lessf(1, 2, "error message %s", "formatted")
+//    a.Lessf(float64(1, "error message %s", "formatted"), float64(2))
+//    a.Lessf("a", "b", "error message %s", "formatted")
+func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Lessf(a.t, e1, e2, msg, args...)
+}
+
 // Nil asserts that the specified object is nil.
 //
 //    a.Nil(err)
@@ -877,6 +1015,32 @@ func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args .
 	return Regexpf(a.t, rx, str, msg, args...)
 }
 
+// Same asserts that two pointers reference the same object.
+//
+//    a.Same(ptr1, ptr2)
+//
+// Both arguments must be pointer variables. Pointer variable sameness is
+// determined based on the equality of both type and value.
+func (a *Assertions) Same(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Same(a.t, expected, actual, msgAndArgs...)
+}
+
+// Samef asserts that two pointers reference the same object.
+//
+//    a.Samef(ptr1, ptr2, "error message %s", "formatted")
+//
+// Both arguments must be pointer variables. Pointer variable sameness is
+// determined based on the equality of both type and value.
+func (a *Assertions) Samef(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Samef(a.t, expected, actual, msg, args...)
+}
+
 // Subset asserts that the specified list(array, slice...) contains all
 // elements given in the specified subset(array, slice...).
 //

+ 309 - 0
vendor/github.com/stretchr/testify/assert/assertion_order.go

@@ -0,0 +1,309 @@
+package assert
+
+import (
+	"fmt"
+	"reflect"
+)
+
+func compare(obj1, obj2 interface{}, kind reflect.Kind) (int, bool) {
+	switch kind {
+	case reflect.Int:
+		{
+			intobj1 := obj1.(int)
+			intobj2 := obj2.(int)
+			if intobj1 > intobj2 {
+				return -1, true
+			}
+			if intobj1 == intobj2 {
+				return 0, true
+			}
+			if intobj1 < intobj2 {
+				return 1, true
+			}
+		}
+	case reflect.Int8:
+		{
+			int8obj1 := obj1.(int8)
+			int8obj2 := obj2.(int8)
+			if int8obj1 > int8obj2 {
+				return -1, true
+			}
+			if int8obj1 == int8obj2 {
+				return 0, true
+			}
+			if int8obj1 < int8obj2 {
+				return 1, true
+			}
+		}
+	case reflect.Int16:
+		{
+			int16obj1 := obj1.(int16)
+			int16obj2 := obj2.(int16)
+			if int16obj1 > int16obj2 {
+				return -1, true
+			}
+			if int16obj1 == int16obj2 {
+				return 0, true
+			}
+			if int16obj1 < int16obj2 {
+				return 1, true
+			}
+		}
+	case reflect.Int32:
+		{
+			int32obj1 := obj1.(int32)
+			int32obj2 := obj2.(int32)
+			if int32obj1 > int32obj2 {
+				return -1, true
+			}
+			if int32obj1 == int32obj2 {
+				return 0, true
+			}
+			if int32obj1 < int32obj2 {
+				return 1, true
+			}
+		}
+	case reflect.Int64:
+		{
+			int64obj1 := obj1.(int64)
+			int64obj2 := obj2.(int64)
+			if int64obj1 > int64obj2 {
+				return -1, true
+			}
+			if int64obj1 == int64obj2 {
+				return 0, true
+			}
+			if int64obj1 < int64obj2 {
+				return 1, true
+			}
+		}
+	case reflect.Uint:
+		{
+			uintobj1 := obj1.(uint)
+			uintobj2 := obj2.(uint)
+			if uintobj1 > uintobj2 {
+				return -1, true
+			}
+			if uintobj1 == uintobj2 {
+				return 0, true
+			}
+			if uintobj1 < uintobj2 {
+				return 1, true
+			}
+		}
+	case reflect.Uint8:
+		{
+			uint8obj1 := obj1.(uint8)
+			uint8obj2 := obj2.(uint8)
+			if uint8obj1 > uint8obj2 {
+				return -1, true
+			}
+			if uint8obj1 == uint8obj2 {
+				return 0, true
+			}
+			if uint8obj1 < uint8obj2 {
+				return 1, true
+			}
+		}
+	case reflect.Uint16:
+		{
+			uint16obj1 := obj1.(uint16)
+			uint16obj2 := obj2.(uint16)
+			if uint16obj1 > uint16obj2 {
+				return -1, true
+			}
+			if uint16obj1 == uint16obj2 {
+				return 0, true
+			}
+			if uint16obj1 < uint16obj2 {
+				return 1, true
+			}
+		}
+	case reflect.Uint32:
+		{
+			uint32obj1 := obj1.(uint32)
+			uint32obj2 := obj2.(uint32)
+			if uint32obj1 > uint32obj2 {
+				return -1, true
+			}
+			if uint32obj1 == uint32obj2 {
+				return 0, true
+			}
+			if uint32obj1 < uint32obj2 {
+				return 1, true
+			}
+		}
+	case reflect.Uint64:
+		{
+			uint64obj1 := obj1.(uint64)
+			uint64obj2 := obj2.(uint64)
+			if uint64obj1 > uint64obj2 {
+				return -1, true
+			}
+			if uint64obj1 == uint64obj2 {
+				return 0, true
+			}
+			if uint64obj1 < uint64obj2 {
+				return 1, true
+			}
+		}
+	case reflect.Float32:
+		{
+			float32obj1 := obj1.(float32)
+			float32obj2 := obj2.(float32)
+			if float32obj1 > float32obj2 {
+				return -1, true
+			}
+			if float32obj1 == float32obj2 {
+				return 0, true
+			}
+			if float32obj1 < float32obj2 {
+				return 1, true
+			}
+		}
+	case reflect.Float64:
+		{
+			float64obj1 := obj1.(float64)
+			float64obj2 := obj2.(float64)
+			if float64obj1 > float64obj2 {
+				return -1, true
+			}
+			if float64obj1 == float64obj2 {
+				return 0, true
+			}
+			if float64obj1 < float64obj2 {
+				return 1, true
+			}
+		}
+	case reflect.String:
+		{
+			stringobj1 := obj1.(string)
+			stringobj2 := obj2.(string)
+			if stringobj1 > stringobj2 {
+				return -1, true
+			}
+			if stringobj1 == stringobj2 {
+				return 0, true
+			}
+			if stringobj1 < stringobj2 {
+				return 1, true
+			}
+		}
+	}
+
+	return 0, false
+}
+
+// Greater asserts that the first element is greater than the second
+//
+//    assert.Greater(t, 2, 1)
+//    assert.Greater(t, float64(2), float64(1))
+//    assert.Greater(t, "b", "a")
+func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+
+	e1Kind := reflect.ValueOf(e1).Kind()
+	e2Kind := reflect.ValueOf(e2).Kind()
+	if e1Kind != e2Kind {
+		return Fail(t, "Elements should be the same type", msgAndArgs...)
+	}
+
+	res, isComparable := compare(e1, e2, e1Kind)
+	if !isComparable {
+		return Fail(t, fmt.Sprintf("Can not compare type \"%s\"", reflect.TypeOf(e1)), msgAndArgs...)
+	}
+
+	if res != -1 {
+		return Fail(t, fmt.Sprintf("\"%v\" is not greater than \"%v\"", e1, e2), msgAndArgs...)
+	}
+
+	return true
+}
+
+// GreaterOrEqual asserts that the first element is greater than or equal to the second
+//
+//    assert.GreaterOrEqual(t, 2, 1)
+//    assert.GreaterOrEqual(t, 2, 2)
+//    assert.GreaterOrEqual(t, "b", "a")
+//    assert.GreaterOrEqual(t, "b", "b")
+func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+
+	e1Kind := reflect.ValueOf(e1).Kind()
+	e2Kind := reflect.ValueOf(e2).Kind()
+	if e1Kind != e2Kind {
+		return Fail(t, "Elements should be the same type", msgAndArgs...)
+	}
+
+	res, isComparable := compare(e1, e2, e1Kind)
+	if !isComparable {
+		return Fail(t, fmt.Sprintf("Can not compare type \"%s\"", reflect.TypeOf(e1)), msgAndArgs...)
+	}
+
+	if res != -1 && res != 0 {
+		return Fail(t, fmt.Sprintf("\"%v\" is not greater than or equal to \"%v\"", e1, e2), msgAndArgs...)
+	}
+
+	return true
+}
+
+// Less asserts that the first element is less than the second
+//
+//    assert.Less(t, 1, 2)
+//    assert.Less(t, float64(1), float64(2))
+//    assert.Less(t, "a", "b")
+func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+
+	e1Kind := reflect.ValueOf(e1).Kind()
+	e2Kind := reflect.ValueOf(e2).Kind()
+	if e1Kind != e2Kind {
+		return Fail(t, "Elements should be the same type", msgAndArgs...)
+	}
+
+	res, isComparable := compare(e1, e2, e1Kind)
+	if !isComparable {
+		return Fail(t, fmt.Sprintf("Can not compare type \"%s\"", reflect.TypeOf(e1)), msgAndArgs...)
+	}
+
+	if res != 1 {
+		return Fail(t, fmt.Sprintf("\"%v\" is not less than \"%v\"", e1, e2), msgAndArgs...)
+	}
+
+	return true
+}
+
+// LessOrEqual asserts that the first element is less than or equal to the second
+//
+//    assert.LessOrEqual(t, 1, 2)
+//    assert.LessOrEqual(t, 2, 2)
+//    assert.LessOrEqual(t, "a", "b")
+//    assert.LessOrEqual(t, "b", "b")
+func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+
+	e1Kind := reflect.ValueOf(e1).Kind()
+	e2Kind := reflect.ValueOf(e2).Kind()
+	if e1Kind != e2Kind {
+		return Fail(t, "Elements should be the same type", msgAndArgs...)
+	}
+
+	res, isComparable := compare(e1, e2, e1Kind)
+	if !isComparable {
+		return Fail(t, fmt.Sprintf("Can not compare type \"%s\"", reflect.TypeOf(e1)), msgAndArgs...)
+	}
+
+	if res != 1 && res != 0 {
+		return Fail(t, fmt.Sprintf("\"%v\" is not less than or equal to \"%v\"", e1, e2), msgAndArgs...)
+	}
+
+	return true
+}

+ 89 - 7
vendor/github.com/stretchr/testify/assert/assertions.go

@@ -18,6 +18,7 @@ import (
 
 	"github.com/davecgh/go-spew/spew"
 	"github.com/pmezard/go-difflib/difflib"
+	yaml "gopkg.in/yaml.v2"
 )
 
 //go:generate go run ../_codegen/main.go -output-package=assert -template=assertion_format.go.tmpl
@@ -350,6 +351,37 @@ func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{})
 
 }
 
+// Same asserts that two pointers reference the same object.
+//
+//    assert.Same(t, ptr1, ptr2)
+//
+// Both arguments must be pointer variables. Pointer variable sameness is
+// determined based on the equality of both type and value.
+func Same(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+
+	expectedPtr, actualPtr := reflect.ValueOf(expected), reflect.ValueOf(actual)
+	if expectedPtr.Kind() != reflect.Ptr || actualPtr.Kind() != reflect.Ptr {
+		return Fail(t, "Invalid operation: both arguments must be pointers", msgAndArgs...)
+	}
+
+	expectedType, actualType := reflect.TypeOf(expected), reflect.TypeOf(actual)
+	if expectedType != actualType {
+		return Fail(t, fmt.Sprintf("Pointer expected to be of type %v, but was %v",
+			expectedType, actualType), msgAndArgs...)
+	}
+
+	if expected != actual {
+		return Fail(t, fmt.Sprintf("Not same: \n"+
+			"expected: %p %#v\n"+
+			"actual  : %p %#v", expected, expected, actual, actual), msgAndArgs...)
+	}
+
+	return true
+}
+
 // formatUnequalValues takes two values of arbitrary types and returns string
 // representations appropriate to be presented to the user.
 //
@@ -479,14 +511,14 @@ func isEmpty(object interface{}) bool {
 	// collection types are empty when they have no element
 	case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
 		return objValue.Len() == 0
-	// pointers are empty if nil or if the value they point to is empty
+		// pointers are empty if nil or if the value they point to is empty
 	case reflect.Ptr:
 		if objValue.IsNil() {
 			return true
 		}
 		deref := objValue.Elem().Interface()
 		return isEmpty(deref)
-	// for all other types, compare against the zero value
+		// for all other types, compare against the zero value
 	default:
 		zero := reflect.Zero(objValue.Type())
 		return reflect.DeepEqual(object, zero.Interface())
@@ -629,7 +661,7 @@ func NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{
 func includeElement(list interface{}, element interface{}) (ok, found bool) {
 
 	listValue := reflect.ValueOf(list)
-	elementValue := reflect.ValueOf(element)
+	listKind := reflect.TypeOf(list).Kind()
 	defer func() {
 		if e := recover(); e != nil {
 			ok = false
@@ -637,11 +669,12 @@ func includeElement(list interface{}, element interface{}) (ok, found bool) {
 		}
 	}()
 
-	if reflect.TypeOf(list).Kind() == reflect.String {
+	if listKind == reflect.String {
+		elementValue := reflect.ValueOf(element)
 		return true, strings.Contains(listValue.String(), elementValue.String())
 	}
 
-	if reflect.TypeOf(list).Kind() == reflect.Map {
+	if listKind == reflect.Map {
 		mapKeys := listValue.MapKeys()
 		for i := 0; i < len(mapKeys); i++ {
 			if ObjectsAreEqual(mapKeys[i].Interface(), element) {
@@ -1337,6 +1370,24 @@ func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{
 	return Equal(t, expectedJSONAsInterface, actualJSONAsInterface, msgAndArgs...)
 }
 
+// YAMLEq asserts that two YAML strings are equivalent.
+func YAMLEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	var expectedYAMLAsInterface, actualYAMLAsInterface interface{}
+
+	if err := yaml.Unmarshal([]byte(expected), &expectedYAMLAsInterface); err != nil {
+		return Fail(t, fmt.Sprintf("Expected value ('%s') is not valid yaml.\nYAML parsing error: '%s'", expected, err.Error()), msgAndArgs...)
+	}
+
+	if err := yaml.Unmarshal([]byte(actual), &actualYAMLAsInterface); err != nil {
+		return Fail(t, fmt.Sprintf("Input ('%s') needs to be valid yaml.\nYAML error: '%s'", actual, err.Error()), msgAndArgs...)
+	}
+
+	return Equal(t, expectedYAMLAsInterface, actualYAMLAsInterface, msgAndArgs...)
+}
+
 func typeAndKind(v interface{}) (reflect.Type, reflect.Kind) {
 	t := reflect.TypeOf(v)
 	k := t.Kind()
@@ -1371,8 +1422,8 @@ func diff(expected interface{}, actual interface{}) string {
 		e = spewConfig.Sdump(expected)
 		a = spewConfig.Sdump(actual)
 	} else {
-		e = expected.(string)
-		a = actual.(string)
+		e = reflect.ValueOf(expected).String()
+		a = reflect.ValueOf(actual).String()
 	}
 
 	diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{
@@ -1414,3 +1465,34 @@ var spewConfig = spew.ConfigState{
 type tHelper interface {
 	Helper()
 }
+
+// Eventually asserts that given condition will be met in waitFor time,
+// periodically checking target function each tick.
+//
+//    assert.Eventually(t, func() bool { return true; }, time.Second, 10*time.Millisecond)
+func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+
+	timer := time.NewTimer(waitFor)
+	ticker := time.NewTicker(tick)
+	checkPassed := make(chan bool)
+	defer timer.Stop()
+	defer ticker.Stop()
+	defer close(checkPassed)
+	for {
+		select {
+		case <-timer.C:
+			return Fail(t, "Condition never satisfied", msgAndArgs...)
+		case result := <-checkPassed:
+			if result {
+				return true
+			}
+		case <-ticker.C:
+			go func() {
+				checkPassed <- condition()
+			}()
+		}
+	}
+}

+ 0 - 3
vendor/golang.org/x/time/AUTHORS

@@ -1,3 +0,0 @@
-# This source code refers to The Go Authors for copyright purposes.
-# The master list of authors is in the main Go distribution,
-# visible at http://tip.golang.org/AUTHORS.

+ 0 - 3
vendor/golang.org/x/time/CONTRIBUTORS

@@ -1,3 +0,0 @@
-# This source code was written by the Go contributors.
-# The master list of contributors is in the main Go distribution,
-# visible at http://tip.golang.org/CONTRIBUTORS.

+ 0 - 27
vendor/golang.org/x/time/LICENSE

@@ -1,27 +0,0 @@
-Copyright (c) 2009 The Go Authors. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
-   * Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
-   * Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the following disclaimer
-in the documentation and/or other materials provided with the
-distribution.
-   * Neither the name of Google Inc. nor the names of its
-contributors may be used to endorse or promote products derived from
-this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 0 - 22
vendor/golang.org/x/time/PATENTS

@@ -1,22 +0,0 @@
-Additional IP Rights Grant (Patents)
-
-"This implementation" means the copyrightable works distributed by
-Google as part of the Go project.
-
-Google 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,
-transfer and otherwise run, modify and propagate the contents of this
-implementation of Go, where such license applies only to those patent
-claims, both currently owned or controlled by Google and acquired in
-the future, licensable by Google that are necessarily infringed by this
-implementation of Go.  This grant does not include claims that would be
-infringed only as a consequence of further modification of this
-implementation.  If you or your agent or exclusive licensee institute or
-order or agree to the institution of patent litigation against any
-entity (including a cross-claim or counterclaim in a lawsuit) alleging
-that this implementation of Go or any code incorporated within this
-implementation of Go constitutes direct or contributory patent
-infringement, or inducement of patent infringement, then any patent
-rights granted to you under this License for this implementation of Go
-shall terminate as of the date such litigation is filed.

+ 0 - 374
vendor/golang.org/x/time/rate/rate.go

@@ -1,374 +0,0 @@
-// Copyright 2015 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 rate provides a rate limiter.
-package rate
-
-import (
-	"context"
-	"fmt"
-	"math"
-	"sync"
-	"time"
-)
-
-// Limit defines the maximum frequency of some events.
-// Limit is represented as number of events per second.
-// A zero Limit allows no events.
-type Limit float64
-
-// Inf is the infinite rate limit; it allows all events (even if burst is zero).
-const Inf = Limit(math.MaxFloat64)
-
-// Every converts a minimum time interval between events to a Limit.
-func Every(interval time.Duration) Limit {
-	if interval <= 0 {
-		return Inf
-	}
-	return 1 / Limit(interval.Seconds())
-}
-
-// A Limiter controls how frequently events are allowed to happen.
-// It implements a "token bucket" of size b, initially full and refilled
-// at rate r tokens per second.
-// Informally, in any large enough time interval, the Limiter limits the
-// rate to r tokens per second, with a maximum burst size of b events.
-// As a special case, if r == Inf (the infinite rate), b is ignored.
-// See https://en.wikipedia.org/wiki/Token_bucket for more about token buckets.
-//
-// The zero value is a valid Limiter, but it will reject all events.
-// Use NewLimiter to create non-zero Limiters.
-//
-// Limiter has three main methods, Allow, Reserve, and Wait.
-// Most callers should use Wait.
-//
-// Each of the three methods consumes a single token.
-// They differ in their behavior when no token is available.
-// If no token is available, Allow returns false.
-// If no token is available, Reserve returns a reservation for a future token
-// and the amount of time the caller must wait before using it.
-// If no token is available, Wait blocks until one can be obtained
-// or its associated context.Context is canceled.
-//
-// The methods AllowN, ReserveN, and WaitN consume n tokens.
-type Limiter struct {
-	limit Limit
-	burst int
-
-	mu     sync.Mutex
-	tokens float64
-	// last is the last time the limiter's tokens field was updated
-	last time.Time
-	// lastEvent is the latest time of a rate-limited event (past or future)
-	lastEvent time.Time
-}
-
-// Limit returns the maximum overall event rate.
-func (lim *Limiter) Limit() Limit {
-	lim.mu.Lock()
-	defer lim.mu.Unlock()
-	return lim.limit
-}
-
-// Burst returns the maximum burst size. Burst is the maximum number of tokens
-// that can be consumed in a single call to Allow, Reserve, or Wait, so higher
-// Burst values allow more events to happen at once.
-// A zero Burst allows no events, unless limit == Inf.
-func (lim *Limiter) Burst() int {
-	return lim.burst
-}
-
-// NewLimiter returns a new Limiter that allows events up to rate r and permits
-// bursts of at most b tokens.
-func NewLimiter(r Limit, b int) *Limiter {
-	return &Limiter{
-		limit: r,
-		burst: b,
-	}
-}
-
-// Allow is shorthand for AllowN(time.Now(), 1).
-func (lim *Limiter) Allow() bool {
-	return lim.AllowN(time.Now(), 1)
-}
-
-// AllowN reports whether n events may happen at time now.
-// Use this method if you intend to drop / skip events that exceed the rate limit.
-// Otherwise use Reserve or Wait.
-func (lim *Limiter) AllowN(now time.Time, n int) bool {
-	return lim.reserveN(now, n, 0).ok
-}
-
-// A Reservation holds information about events that are permitted by a Limiter to happen after a delay.
-// A Reservation may be canceled, which may enable the Limiter to permit additional events.
-type Reservation struct {
-	ok        bool
-	lim       *Limiter
-	tokens    int
-	timeToAct time.Time
-	// This is the Limit at reservation time, it can change later.
-	limit Limit
-}
-
-// OK returns whether the limiter can provide the requested number of tokens
-// within the maximum wait time.  If OK is false, Delay returns InfDuration, and
-// Cancel does nothing.
-func (r *Reservation) OK() bool {
-	return r.ok
-}
-
-// Delay is shorthand for DelayFrom(time.Now()).
-func (r *Reservation) Delay() time.Duration {
-	return r.DelayFrom(time.Now())
-}
-
-// InfDuration is the duration returned by Delay when a Reservation is not OK.
-const InfDuration = time.Duration(1<<63 - 1)
-
-// DelayFrom returns the duration for which the reservation holder must wait
-// before taking the reserved action.  Zero duration means act immediately.
-// InfDuration means the limiter cannot grant the tokens requested in this
-// Reservation within the maximum wait time.
-func (r *Reservation) DelayFrom(now time.Time) time.Duration {
-	if !r.ok {
-		return InfDuration
-	}
-	delay := r.timeToAct.Sub(now)
-	if delay < 0 {
-		return 0
-	}
-	return delay
-}
-
-// Cancel is shorthand for CancelAt(time.Now()).
-func (r *Reservation) Cancel() {
-	r.CancelAt(time.Now())
-	return
-}
-
-// CancelAt indicates that the reservation holder will not perform the reserved action
-// and reverses the effects of this Reservation on the rate limit as much as possible,
-// considering that other reservations may have already been made.
-func (r *Reservation) CancelAt(now time.Time) {
-	if !r.ok {
-		return
-	}
-
-	r.lim.mu.Lock()
-	defer r.lim.mu.Unlock()
-
-	if r.lim.limit == Inf || r.tokens == 0 || r.timeToAct.Before(now) {
-		return
-	}
-
-	// calculate tokens to restore
-	// The duration between lim.lastEvent and r.timeToAct tells us how many tokens were reserved
-	// after r was obtained. These tokens should not be restored.
-	restoreTokens := float64(r.tokens) - r.limit.tokensFromDuration(r.lim.lastEvent.Sub(r.timeToAct))
-	if restoreTokens <= 0 {
-		return
-	}
-	// advance time to now
-	now, _, tokens := r.lim.advance(now)
-	// calculate new number of tokens
-	tokens += restoreTokens
-	if burst := float64(r.lim.burst); tokens > burst {
-		tokens = burst
-	}
-	// update state
-	r.lim.last = now
-	r.lim.tokens = tokens
-	if r.timeToAct == r.lim.lastEvent {
-		prevEvent := r.timeToAct.Add(r.limit.durationFromTokens(float64(-r.tokens)))
-		if !prevEvent.Before(now) {
-			r.lim.lastEvent = prevEvent
-		}
-	}
-
-	return
-}
-
-// Reserve is shorthand for ReserveN(time.Now(), 1).
-func (lim *Limiter) Reserve() *Reservation {
-	return lim.ReserveN(time.Now(), 1)
-}
-
-// ReserveN returns a Reservation that indicates how long the caller must wait before n events happen.
-// The Limiter takes this Reservation into account when allowing future events.
-// ReserveN returns false if n exceeds the Limiter's burst size.
-// Usage example:
-//   r := lim.ReserveN(time.Now(), 1)
-//   if !r.OK() {
-//     // Not allowed to act! Did you remember to set lim.burst to be > 0 ?
-//     return
-//   }
-//   time.Sleep(r.Delay())
-//   Act()
-// Use this method if you wish to wait and slow down in accordance with the rate limit without dropping events.
-// If you need to respect a deadline or cancel the delay, use Wait instead.
-// To drop or skip events exceeding rate limit, use Allow instead.
-func (lim *Limiter) ReserveN(now time.Time, n int) *Reservation {
-	r := lim.reserveN(now, n, InfDuration)
-	return &r
-}
-
-// Wait is shorthand for WaitN(ctx, 1).
-func (lim *Limiter) Wait(ctx context.Context) (err error) {
-	return lim.WaitN(ctx, 1)
-}
-
-// WaitN blocks until lim permits n events to happen.
-// It returns an error if n exceeds the Limiter's burst size, the Context is
-// canceled, or the expected wait time exceeds the Context's Deadline.
-// The burst limit is ignored if the rate limit is Inf.
-func (lim *Limiter) WaitN(ctx context.Context, n int) (err error) {
-	if n > lim.burst && lim.limit != Inf {
-		return fmt.Errorf("rate: Wait(n=%d) exceeds limiter's burst %d", n, lim.burst)
-	}
-	// Check if ctx is already cancelled
-	select {
-	case <-ctx.Done():
-		return ctx.Err()
-	default:
-	}
-	// Determine wait limit
-	now := time.Now()
-	waitLimit := InfDuration
-	if deadline, ok := ctx.Deadline(); ok {
-		waitLimit = deadline.Sub(now)
-	}
-	// Reserve
-	r := lim.reserveN(now, n, waitLimit)
-	if !r.ok {
-		return fmt.Errorf("rate: Wait(n=%d) would exceed context deadline", n)
-	}
-	// Wait if necessary
-	delay := r.DelayFrom(now)
-	if delay == 0 {
-		return nil
-	}
-	t := time.NewTimer(delay)
-	defer t.Stop()
-	select {
-	case <-t.C:
-		// We can proceed.
-		return nil
-	case <-ctx.Done():
-		// Context was canceled before we could proceed.  Cancel the
-		// reservation, which may permit other events to proceed sooner.
-		r.Cancel()
-		return ctx.Err()
-	}
-}
-
-// SetLimit is shorthand for SetLimitAt(time.Now(), newLimit).
-func (lim *Limiter) SetLimit(newLimit Limit) {
-	lim.SetLimitAt(time.Now(), newLimit)
-}
-
-// SetLimitAt sets a new Limit for the limiter. The new Limit, and Burst, may be violated
-// or underutilized by those which reserved (using Reserve or Wait) but did not yet act
-// before SetLimitAt was called.
-func (lim *Limiter) SetLimitAt(now time.Time, newLimit Limit) {
-	lim.mu.Lock()
-	defer lim.mu.Unlock()
-
-	now, _, tokens := lim.advance(now)
-
-	lim.last = now
-	lim.tokens = tokens
-	lim.limit = newLimit
-}
-
-// reserveN is a helper method for AllowN, ReserveN, and WaitN.
-// maxFutureReserve specifies the maximum reservation wait duration allowed.
-// reserveN returns Reservation, not *Reservation, to avoid allocation in AllowN and WaitN.
-func (lim *Limiter) reserveN(now time.Time, n int, maxFutureReserve time.Duration) Reservation {
-	lim.mu.Lock()
-
-	if lim.limit == Inf {
-		lim.mu.Unlock()
-		return Reservation{
-			ok:        true,
-			lim:       lim,
-			tokens:    n,
-			timeToAct: now,
-		}
-	}
-
-	now, last, tokens := lim.advance(now)
-
-	// Calculate the remaining number of tokens resulting from the request.
-	tokens -= float64(n)
-
-	// Calculate the wait duration
-	var waitDuration time.Duration
-	if tokens < 0 {
-		waitDuration = lim.limit.durationFromTokens(-tokens)
-	}
-
-	// Decide result
-	ok := n <= lim.burst && waitDuration <= maxFutureReserve
-
-	// Prepare reservation
-	r := Reservation{
-		ok:    ok,
-		lim:   lim,
-		limit: lim.limit,
-	}
-	if ok {
-		r.tokens = n
-		r.timeToAct = now.Add(waitDuration)
-	}
-
-	// Update state
-	if ok {
-		lim.last = now
-		lim.tokens = tokens
-		lim.lastEvent = r.timeToAct
-	} else {
-		lim.last = last
-	}
-
-	lim.mu.Unlock()
-	return r
-}
-
-// advance calculates and returns an updated state for lim resulting from the passage of time.
-// lim is not changed.
-func (lim *Limiter) advance(now time.Time) (newNow time.Time, newLast time.Time, newTokens float64) {
-	last := lim.last
-	if now.Before(last) {
-		last = now
-	}
-
-	// Avoid making delta overflow below when last is very old.
-	maxElapsed := lim.limit.durationFromTokens(float64(lim.burst) - lim.tokens)
-	elapsed := now.Sub(last)
-	if elapsed > maxElapsed {
-		elapsed = maxElapsed
-	}
-
-	// Calculate the new number of tokens, due to time that passed.
-	delta := lim.limit.tokensFromDuration(elapsed)
-	tokens := lim.tokens + delta
-	if burst := float64(lim.burst); tokens > burst {
-		tokens = burst
-	}
-
-	return now, last, tokens
-}
-
-// durationFromTokens is a unit conversion function from the number of tokens to the duration
-// of time it takes to accumulate them at a rate of limit tokens per second.
-func (limit Limit) durationFromTokens(tokens float64) time.Duration {
-	seconds := tokens / float64(limit)
-	return time.Nanosecond * time.Duration(1e9*seconds)
-}
-
-// tokensFromDuration is a unit conversion function from a time duration to the number of tokens
-// which could be accumulated during that duration at a rate of limit tokens per second.
-func (limit Limit) tokensFromDuration(d time.Duration) float64 {
-	return d.Seconds() * float64(limit)
-}

+ 2 - 0
vendor/gopkg.in/ini.v1/.travis.yml

@@ -7,7 +7,9 @@ go:
   - 1.9.x
   - 1.10.x
   - 1.11.x
+  - 1.12.x
 
+install: skip
 script:
   - go get golang.org/x/tools/cmd/cover
   - go get github.com/smartystreets/goconvey

+ 14 - 6
vendor/gopkg.in/ini.v1/README.md

@@ -22,19 +22,27 @@ Package ini provides INI file read and write functionality in Go.
 
 The minimum requirement of Go is **1.6**.
 
-To use a tagged revision:
-
 ```sh
 $ go get gopkg.in/ini.v1
 ```
 
-To use with latest changes:
+Please add `-u` flag to update in the future.
+
+## Go Modules
+
+For historical reason, people use two different import paths for this package: `github.com/go-ini/ini` and `gopkg.in/ini.v1`. If you get error similar to the following one:
 
-```sh
-$ go get github.com/go-ini/ini
+```
+go: finding github.com/go-ini/ini v0.0.0-00010101000000-000000000000
+go: github.com/go-ini/ini@v0.0.0-00010101000000-000000000000: unknown revision 000000000000
+go: error loading module requirements
 ```
 
-Please add `-u` flag to update in the future.
+It is because one of your dependencies is using deprecated import path `github.com/go-ini/ini`, you can make a quick fix by adding the following line to your `go.mod` file (`v.1.44.0` was the latest version tagged on `master` branch):
+
+```
+replace github.com/go-ini/ini => gopkg.in/ini.v1 v1.44.0
+```
 
 ## Getting Help
 

+ 2 - 0
vendor/gopkg.in/ini.v1/error.go

@@ -18,10 +18,12 @@ 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

+ 6 - 6
vendor/gopkg.in/ini.v1/file.go

@@ -68,7 +68,7 @@ func Empty() *File {
 func (f *File) NewSection(name string) (*Section, error) {
 	if len(name) == 0 {
 		return nil, errors.New("error creating new section: empty section name")
-	} else if f.options.Insensitive && name != DEFAULT_SECTION {
+	} else if f.options.Insensitive && name != DefaultSection {
 		name = strings.ToLower(name)
 	}
 
@@ -111,7 +111,7 @@ func (f *File) NewSections(names ...string) (err error) {
 // GetSection returns section by given name.
 func (f *File) GetSection(name string) (*Section, error) {
 	if len(name) == 0 {
-		name = DEFAULT_SECTION
+		name = DefaultSection
 	}
 	if f.options.Insensitive {
 		name = strings.ToLower(name)
@@ -141,7 +141,7 @@ func (f *File) Section(name string) *Section {
 	return sec
 }
 
-// Section returns list of Section.
+// Sections returns a list of Section stored in the current instance.
 func (f *File) Sections() []*Section {
 	if f.BlockMode {
 		f.lock.RLock()
@@ -175,7 +175,7 @@ func (f *File) DeleteSection(name string) {
 	}
 
 	if len(name) == 0 {
-		name = DEFAULT_SECTION
+		name = DefaultSection
 	}
 
 	for i, s := range f.sectionList {
@@ -306,7 +306,7 @@ func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) {
 		for _, kname := range sec.keyList {
 			key := sec.Key(kname)
 			if len(key.Comment) > 0 {
-				if len(indent) > 0 && sname != DEFAULT_SECTION {
+				if len(indent) > 0 && sname != DefaultSection {
 					buf.WriteString(indent)
 				}
 
@@ -325,7 +325,7 @@ func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) {
 				}
 			}
 
-			if len(indent) > 0 && sname != DEFAULT_SECTION {
+			if len(indent) > 0 && sname != DefaultSection {
 				buf.WriteString(indent)
 			}
 

+ 18 - 14
vendor/gopkg.in/ini.v1/ini.go

@@ -28,44 +28,46 @@ import (
 )
 
 const (
-	// Name for default section. You can use this constant or the string literal.
+	// 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.
-	DEFAULT_SECTION = "DEFAULT"
+	DefaultSection = "DEFAULT"
+	// Deprecated: Use "DefaultSection" instead.
+	DEFAULT_SECTION = DefaultSection
 
 	// Maximum allowed depth when recursively substituing variable names.
-	_DEPTH_VALUES = 99
-	_VERSION      = "1.42.0"
+	depthValues = 99
+	version     = "1.46.0"
 )
 
 // Version returns current package version literal.
 func Version() string {
-	return _VERSION
+	return version
 }
 
 var (
-	// Delimiter to determine or compose a new line.
-	// This variable will be changed to "\r\n" automatically on Windows
-	// at package init time.
+	// 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"
 
-	// Place custom spaces when PrettyFormat and PrettyEqual are both disabled
-	DefaultFormatLeft  = ""
+	// 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 = ""
 
 	// Variable regexp pattern: %(variable)s
 	varPattern = regexp.MustCompile(`%\(([^\)]+)\)s`)
 
-	// Indicate whether to align "=" sign with spaces to produce pretty output
+	// PrettyFormat indicates whether to align "=" sign with spaces to produce pretty output
 	// or reduce all possible spaces for compact format.
 	PrettyFormat = true
 
-	// Place spaces around "=" sign even when PrettyFormat is false
+	// PrettyEqual places spaces around "=" sign even when PrettyFormat is false.
 	PrettyEqual = false
 
-	// Explicitly write DEFAULT section header
+	// DefaultHeader explicitly writes default section header.
 	DefaultHeader = false
 
-	// Indicate whether to put a line between sections
+	// PrettySection indicates whether to put a line between sections.
 	PrettySection = true
 )
 
@@ -129,6 +131,7 @@ func parseDataSource(source interface{}) (dataSource, error) {
 	}
 }
 
+// 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
@@ -174,6 +177,7 @@ type LoadOptions struct {
 	PreserveSurroundedQuote bool
 }
 
+// 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)

+ 6 - 5
vendor/gopkg.in/ini.v1/key.go

@@ -77,6 +77,7 @@ func (k *Key) addNestedValue(val string) error {
 	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")
@@ -126,7 +127,7 @@ func (k *Key) transformValue(val string) string {
 	if !strings.Contains(val, "%") {
 		return val
 	}
-	for i := 0; i < _DEPTH_VALUES; i++ {
+	for i := 0; i < depthValues; i++ {
 		vr := varPattern.FindString(val)
 		if len(vr) == 0 {
 			break
@@ -186,8 +187,8 @@ func (k *Key) Float64() (float64, error) {
 
 // Int returns int type value.
 func (k *Key) Int() (int, error) {
-    v, err := strconv.ParseInt(k.String(), 0, 64)
-    return int(v), err
+	v, err := strconv.ParseInt(k.String(), 0, 64)
+	return int(v), err
 }
 
 // Int64 returns int64 type value.
@@ -491,7 +492,7 @@ func (k *Key) Strings(delim string) []string {
 				buf.WriteRune(runes[idx])
 			}
 		}
-		idx += 1
+		idx++
 		if idx == len(runes) {
 			break
 		}
@@ -669,7 +670,7 @@ func (k *Key) parseInts(strs []string, addInvalid, returnOnInvalid bool) ([]int,
 	vals := make([]int, 0, len(strs))
 	for _, str := range strs {
 		valInt64, err := strconv.ParseInt(str, 0, 64)
-		val := int(valInt64)        
+		val := int(valInt64)
 		if err != nil && returnOnInvalid {
 			return nil, err
 		}

+ 67 - 68
vendor/gopkg.in/ini.v1/parser.go

@@ -27,25 +27,29 @@ import (
 
 var pythonMultiline = regexp.MustCompile("^(\\s+)([^\n]+)")
 
-type tokenType int
-
-const (
-	_TOKEN_INVALID tokenType = iota
-	_TOKEN_COMMENT
-	_TOKEN_SECTION
-	_TOKEN_KEY
-)
+type parserOptions struct {
+	IgnoreContinuation          bool
+	IgnoreInlineComment         bool
+	AllowPythonMultilineValues  bool
+	SpaceBeforeInlineComment    bool
+	UnescapeValueDoubleQuotes   bool
+	UnescapeValueCommentSymbols bool
+	PreserveSurroundedQuote     bool
+}
 
 type parser struct {
 	buf     *bufio.Reader
+	options parserOptions
+
 	isEOF   bool
 	count   int
 	comment *bytes.Buffer
 }
 
-func newParser(r io.Reader) *parser {
+func newParser(r io.Reader, opts parserOptions) *parser {
 	return &parser{
 		buf:     bufio.NewReader(r),
+		options: opts,
 		count:   1,
 		comment: &bytes.Buffer{},
 	}
@@ -196,12 +200,13 @@ func hasSurroundedQuote(in string, quote byte) bool {
 		strings.IndexByte(in[1:], quote) == len(in)-2
 }
 
-func (p *parser) readValue(in []byte,
-	parserBufferSize int,
-	ignoreContinuation, ignoreInlineComment, unescapeValueDoubleQuotes, unescapeValueCommentSymbols, allowPythonMultilines, spaceBeforeInlineComment, preserveSurroundedQuote bool) (string, error) {
+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
 	}
 
@@ -210,7 +215,7 @@ func (p *parser) readValue(in []byte,
 		valQuote = `"""`
 	} else if line[0] == '`' {
 		valQuote = "`"
-	} else if unescapeValueDoubleQuotes && line[0] == '"' {
+	} else if p.options.UnescapeValueDoubleQuotes && line[0] == '"' {
 		valQuote = `"`
 	}
 
@@ -222,7 +227,7 @@ func (p *parser) readValue(in []byte,
 			return p.readMultilines(line, line[startIdx:], valQuote)
 		}
 
-		if unescapeValueDoubleQuotes && valQuote == `"` {
+		if p.options.UnescapeValueDoubleQuotes && valQuote == `"` {
 			return strings.Replace(line[startIdx:pos+startIdx], `\"`, `"`, -1), nil
 		}
 		return line[startIdx : pos+startIdx], nil
@@ -234,14 +239,14 @@ func (p *parser) readValue(in []byte,
 	trimmedLastChar := line[len(line)-1]
 
 	// Check continuation lines when desired
-	if !ignoreContinuation && trimmedLastChar == '\\' {
+	if !p.options.IgnoreContinuation && trimmedLastChar == '\\' {
 		return p.readContinuationLines(line[:len(line)-1])
 	}
 
 	// Check if ignore inline comment
-	if !ignoreInlineComment {
+	if !p.options.IgnoreInlineComment {
 		var i int
-		if spaceBeforeInlineComment {
+		if p.options.SpaceBeforeInlineComment {
 			i = strings.Index(line, " #")
 			if i == -1 {
 				i = strings.Index(line, " ;")
@@ -260,65 +265,75 @@ func (p *parser) readValue(in []byte,
 
 	// Trim single and double quotes
 	if (hasSurroundedQuote(line, '\'') ||
-		hasSurroundedQuote(line, '"')) && !preserveSurroundedQuote {
+		hasSurroundedQuote(line, '"')) && !p.options.PreserveSurroundedQuote {
 		line = line[1 : len(line)-1]
-	} else if len(valQuote) == 0 && unescapeValueCommentSymbols {
+	} 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 allowPythonMultilines && lastChar == '\n' {
-		parserBufferPeekResult, _ := p.buf.Peek(parserBufferSize)
-		peekBuffer := bytes.NewBuffer(parserBufferPeekResult)
+	} else if p.options.AllowPythonMultilineValues && lastChar == '\n' {
+		return p.readPythonMultilines(line, bufferSize)
+	}
 
-		val := line
+	return line, nil
+}
 
-		for {
-			peekData, peekErr := peekBuffer.ReadBytes('\n')
-			if peekErr != nil {
-				if peekErr == io.EOF {
-					return val, nil
-				}
-				return "", peekErr
-			}
+func (p *parser) readPythonMultilines(line string, bufferSize int) (string, error) {
+	parserBufferPeekResult, _ := p.buf.Peek(bufferSize)
+	peekBuffer := bytes.NewBuffer(parserBufferPeekResult)
 
-			peekMatches := pythonMultiline.FindStringSubmatch(string(peekData))
-			if len(peekMatches) != 3 {
-				return val, nil
+	for {
+		peekData, peekErr := peekBuffer.ReadBytes('\n')
+		if peekErr != nil {
+			if peekErr == io.EOF {
+				return line, nil
 			}
+			return "", peekErr
+		}
 
-			// NOTE: Return if not a python-ini multi-line value.
-			currentIdentSize := len(peekMatches[1])
-			if currentIdentSize <= 0 {
-				return val, nil
-			}
+		peekMatches := pythonMultiline.FindStringSubmatch(string(peekData))
+		if len(peekMatches) != 3 {
+			return line, nil
+		}
 
-			// NOTE: Just advance the parser reader (buffer) in-sync with the peek buffer.
-			_, err := p.readUntil('\n')
-			if err != nil {
-				return "", err
-			}
+		// NOTE: Return if not a python-ini multi-line value.
+		currentIdentSize := len(peekMatches[1])
+		if currentIdentSize <= 0 {
+			return line, nil
+		}
 
-			val += fmt.Sprintf("\n%s", peekMatches[2])
+		// NOTE: Just advance the parser reader (buffer) in-sync with the peek buffer.
+		_, err := p.readUntil('\n')
+		if err != nil {
+			return "", err
 		}
-	}
 
-	return line, nil
+		line += fmt.Sprintf("\n%s", peekMatches[2])
+	}
 }
 
 // parse parses data through an io.Reader.
 func (f *File) parse(reader io.Reader) (err error) {
-	p := newParser(reader)
+	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,
+	})
 	if err = p.BOM(); err != nil {
 		return fmt.Errorf("BOM: %v", err)
 	}
 
 	// Ignore error because default section name is never empty string.
-	name := DEFAULT_SECTION
+	name := DefaultSection
 	if f.options.Insensitive {
-		name = strings.ToLower(DEFAULT_SECTION)
+		name = strings.ToLower(DefaultSection)
 	}
 	section, _ := f.NewSection(name)
 
@@ -426,15 +441,7 @@ func (f *File) parse(reader io.Reader) (err error) {
 			if IsErrDelimiterNotFound(err) {
 				switch {
 				case f.options.AllowBooleanKeys:
-					kname, err := p.readValue(line,
-						parserBufferSize,
-						f.options.IgnoreContinuation,
-						f.options.IgnoreInlineComment,
-						f.options.UnescapeValueDoubleQuotes,
-						f.options.UnescapeValueCommentSymbols,
-						f.options.AllowPythonMultilineValues,
-						f.options.SpaceBeforeInlineComment,
-						f.options.PreserveSurroundedQuote)
+					kname, err := p.readValue(line, parserBufferSize)
 					if err != nil {
 						return err
 					}
@@ -461,15 +468,7 @@ func (f *File) parse(reader io.Reader) (err error) {
 			p.count++
 		}
 
-		value, err := p.readValue(line[offset:],
-			parserBufferSize,
-			f.options.IgnoreContinuation,
-			f.options.IgnoreInlineComment,
-			f.options.UnescapeValueDoubleQuotes,
-			f.options.UnescapeValueCommentSymbols,
-			f.options.AllowPythonMultilineValues,
-			f.options.SpaceBeforeInlineComment,
-			f.options.PreserveSurroundedQuote)
+		value, err := p.readValue(line[offset:], parserBufferSize)
 		if err != nil {
 			return err
 		}

+ 2 - 5
vendor/gopkg.in/ini.v1/section.go

@@ -106,7 +106,6 @@ func (s *Section) NewBooleanKey(name string) (*Key, error) {
 
 // GetKey returns key in section by given name.
 func (s *Section) GetKey(name string) (*Key, error) {
-	// FIXME: change to section level lock?
 	if s.f.BlockMode {
 		s.f.lock.RLock()
 	}
@@ -129,9 +128,8 @@ func (s *Section) GetKey(name string) (*Key, error) {
 					continue
 				}
 				return sec.GetKey(name)
-			} else {
-				break
 			}
+			break
 		}
 		return nil, fmt.Errorf("error when getting key of section '%s': key '%s' not exists", s.name, name)
 	}
@@ -144,8 +142,7 @@ func (s *Section) HasKey(name string) bool {
 	return key != nil
 }
 
-// Haskey is a backwards-compatible name for HasKey.
-// TODO: delete me in v2
+// Deprecated: Use "HasKey" instead.
 func (s *Section) Haskey(name string) bool {
 	return s.HasKey(name)
 }

+ 67 - 16
vendor/gopkg.in/ini.v1/struct.go

@@ -149,7 +149,7 @@ func wrapStrictError(err error, isStrict bool) error {
 
 // 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 strcut.
+// 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 {
 	switch t.Kind() {
 	case reflect.String:
@@ -205,6 +205,17 @@ func setWithProperType(t reflect.Type, key *Key, field reflect.Value, delim stri
 		field.Set(reflect.ValueOf(timeVal))
 	case reflect.Slice:
 		return setSliceWithProperType(key, field, delim, allowShadow, isStrict)
+	case reflect.Ptr:
+		switch t.Elem().Kind() {
+		case reflect.Bool:
+			boolVal, err := key.Bool()
+			if err != nil {
+				return wrapStrictError(err, isStrict)
+			}
+			field.Set(reflect.ValueOf(&boolVal))
+		default:
+			return fmt.Errorf("unsupported type '%s'", t)
+		}
 	default:
 		return fmt.Errorf("unsupported type '%s'", t)
 	}
@@ -244,14 +255,21 @@ func (s *Section) mapTo(val reflect.Value, isStrict bool) error {
 			continue
 		}
 
-		isAnonymous := tpField.Type.Kind() == reflect.Ptr && tpField.Anonymous
 		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 {
+		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.mapTo(field, isStrict); err != nil {
 					return fmt.Errorf("error mapping field(%s): %v", fieldName, err)
 				}
@@ -283,7 +301,7 @@ func (s *Section) MapTo(v interface{}) error {
 	return s.mapTo(val, false)
 }
 
-// MapTo maps section to given struct in strict mode,
+// 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 {
 	typ := reflect.TypeOf(v)
@@ -303,13 +321,13 @@ func (f *File) MapTo(v interface{}) error {
 	return f.Section("").MapTo(v)
 }
 
-// MapTo maps file to given struct in strict mode,
+// 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)
 }
 
-// MapTo maps data sources to given struct with name mapper.
+// 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 {
@@ -342,14 +360,43 @@ func StrictMapTo(v, source interface{}, others ...interface{}) error {
 }
 
 // reflectSliceWithProperType does the opposite thing as setSliceWithProperType.
-func reflectSliceWithProperType(key *Key, field reflect.Value, delim string) error {
+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 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
-	sliceOf := field.Type().Elem().Kind()
 	for i := 0; i < field.Len(); i++ {
 		switch sliceOf {
 		case reflect.String:
@@ -367,12 +414,12 @@ func reflectSliceWithProperType(key *Key, field reflect.Value, delim string) err
 		}
 		buf.WriteString(delim)
 	}
-	key.SetValue(buf.String()[:buf.Len()-1])
+	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) error {
+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())
@@ -387,7 +434,11 @@ func reflectWithProperType(t reflect.Type, key *Key, field reflect.Value, delim
 	case reflectTime:
 		key.SetValue(fmt.Sprint(field.Interface().(time.Time).Format(time.RFC3339)))
 	case reflect.Slice:
-		return reflectSliceWithProperType(key, field, delim)
+		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 '%s'", t)
 	}
@@ -432,12 +483,12 @@ func (s *Section) reflectFrom(val reflect.Value) error {
 			continue
 		}
 
-		opts := strings.SplitN(tag, ",", 2)
-		if len(opts) == 2 && opts[1] == "omitempty" && isEmptyValue(field) {
+		rawName, omitEmpty, allowShadow := parseTagOptions(tag)
+		if omitEmpty && isEmptyValue(field) {
 			continue
 		}
 
-		fieldName := s.parseFieldName(tpField.Name, opts[0])
+		fieldName := s.parseFieldName(tpField.Name, rawName)
 		if len(fieldName) == 0 || !field.CanSet() {
 			continue
 		}
@@ -473,7 +524,7 @@ func (s *Section) reflectFrom(val reflect.Value) error {
 			key.Comment = tpField.Tag.Get("comment")
 		}
 
-		if err = reflectWithProperType(tpField.Type, key, field, parseDelim(tpField.Tag.Get("delim"))); err != nil {
+		if err = reflectWithProperType(tpField.Type, key, field, parseDelim(tpField.Tag.Get("delim")), allowShadow); err != nil {
 			return fmt.Errorf("error reflecting field (%s): %v", fieldName, err)
 		}
 
@@ -500,7 +551,7 @@ func (f *File) ReflectFrom(v interface{}) error {
 	return f.Section("").ReflectFrom(v)
 }
 
-// ReflectFrom reflects data sources from given struct with name mapper.
+// 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)

+ 12 - 0
vendor/gopkg.in/yaml.v2/.travis.yml

@@ -0,0 +1,12 @@
+language: go
+
+go:
+    - 1.4
+    - 1.5
+    - 1.6
+    - 1.7
+    - 1.8
+    - 1.9
+    - tip
+
+go_import_path: gopkg.in/yaml.v2

+ 201 - 0
vendor/gopkg.in/yaml.v2/LICENSE

@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright {yyyy} {name of copyright owner}
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.

+ 31 - 0
vendor/gopkg.in/yaml.v2/LICENSE.libyaml

@@ -0,0 +1,31 @@
+The following files were ported to Go from C files of libyaml, and thus
+are still covered by their original copyright and license:
+
+    apic.go
+    emitterc.go
+    parserc.go
+    readerc.go
+    scannerc.go
+    writerc.go
+    yamlh.go
+    yamlprivateh.go
+
+Copyright (c) 2006 Kirill Simonov
+
+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.

+ 13 - 0
vendor/gopkg.in/yaml.v2/NOTICE

@@ -0,0 +1,13 @@
+Copyright 2011-2016 Canonical Ltd.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.

+ 133 - 0
vendor/gopkg.in/yaml.v2/README.md

@@ -0,0 +1,133 @@
+# YAML support for the Go language
+
+Introduction
+------------
+
+The yaml package enables Go programs to comfortably encode and decode YAML
+values. It was developed within [Canonical](https://www.canonical.com) as
+part of the [juju](https://juju.ubuntu.com) project, and is based on a
+pure Go port of the well-known [libyaml](http://pyyaml.org/wiki/LibYAML)
+C library to parse and generate YAML data quickly and reliably.
+
+Compatibility
+-------------
+
+The yaml package supports most of YAML 1.1 and 1.2, including support for
+anchors, tags, map merging, etc. Multi-document unmarshalling is not yet
+implemented, and base-60 floats from YAML 1.1 are purposefully not
+supported since they're a poor design and are gone in YAML 1.2.
+
+Installation and usage
+----------------------
+
+The import path for the package is *gopkg.in/yaml.v2*.
+
+To install it, run:
+
+    go get gopkg.in/yaml.v2
+
+API documentation
+-----------------
+
+If opened in a browser, the import path itself leads to the API documentation:
+
+  * [https://gopkg.in/yaml.v2](https://gopkg.in/yaml.v2)
+
+API stability
+-------------
+
+The package API for yaml v2 will remain stable as described in [gopkg.in](https://gopkg.in).
+
+
+License
+-------
+
+The yaml package is licensed under the Apache License 2.0. Please see the LICENSE file for details.
+
+
+Example
+-------
+
+```Go
+package main
+
+import (
+        "fmt"
+        "log"
+
+        "gopkg.in/yaml.v2"
+)
+
+var data = `
+a: Easy!
+b:
+  c: 2
+  d: [3, 4]
+`
+
+// Note: struct fields must be public in order for unmarshal to
+// correctly populate the data.
+type T struct {
+        A string
+        B struct {
+                RenamedC int   `yaml:"c"`
+                D        []int `yaml:",flow"`
+        }
+}
+
+func main() {
+        t := T{}
+    
+        err := yaml.Unmarshal([]byte(data), &t)
+        if err != nil {
+                log.Fatalf("error: %v", err)
+        }
+        fmt.Printf("--- t:\n%v\n\n", t)
+    
+        d, err := yaml.Marshal(&t)
+        if err != nil {
+                log.Fatalf("error: %v", err)
+        }
+        fmt.Printf("--- t dump:\n%s\n\n", string(d))
+    
+        m := make(map[interface{}]interface{})
+    
+        err = yaml.Unmarshal([]byte(data), &m)
+        if err != nil {
+                log.Fatalf("error: %v", err)
+        }
+        fmt.Printf("--- m:\n%v\n\n", m)
+    
+        d, err = yaml.Marshal(&m)
+        if err != nil {
+                log.Fatalf("error: %v", err)
+        }
+        fmt.Printf("--- m dump:\n%s\n\n", string(d))
+}
+```
+
+This example will generate the following output:
+
+```
+--- t:
+{Easy! {2 [3 4]}}
+
+--- t dump:
+a: Easy!
+b:
+  c: 2
+  d: [3, 4]
+
+
+--- m:
+map[a:Easy! b:map[c:2 d:[3 4]]]
+
+--- m dump:
+a: Easy!
+b:
+  c: 2
+  d:
+  - 3
+  - 4
+```
+

+ 739 - 0
vendor/gopkg.in/yaml.v2/apic.go

@@ -0,0 +1,739 @@
+package yaml
+
+import (
+	"io"
+)
+
+func yaml_insert_token(parser *yaml_parser_t, pos int, token *yaml_token_t) {
+	//fmt.Println("yaml_insert_token", "pos:", pos, "typ:", token.typ, "head:", parser.tokens_head, "len:", len(parser.tokens))
+
+	// Check if we can move the queue at the beginning of the buffer.
+	if parser.tokens_head > 0 && len(parser.tokens) == cap(parser.tokens) {
+		if parser.tokens_head != len(parser.tokens) {
+			copy(parser.tokens, parser.tokens[parser.tokens_head:])
+		}
+		parser.tokens = parser.tokens[:len(parser.tokens)-parser.tokens_head]
+		parser.tokens_head = 0
+	}
+	parser.tokens = append(parser.tokens, *token)
+	if pos < 0 {
+		return
+	}
+	copy(parser.tokens[parser.tokens_head+pos+1:], parser.tokens[parser.tokens_head+pos:])
+	parser.tokens[parser.tokens_head+pos] = *token
+}
+
+// Create a new parser object.
+func yaml_parser_initialize(parser *yaml_parser_t) bool {
+	*parser = yaml_parser_t{
+		raw_buffer: make([]byte, 0, input_raw_buffer_size),
+		buffer:     make([]byte, 0, input_buffer_size),
+	}
+	return true
+}
+
+// Destroy a parser object.
+func yaml_parser_delete(parser *yaml_parser_t) {
+	*parser = yaml_parser_t{}
+}
+
+// String read handler.
+func yaml_string_read_handler(parser *yaml_parser_t, buffer []byte) (n int, err error) {
+	if parser.input_pos == len(parser.input) {
+		return 0, io.EOF
+	}
+	n = copy(buffer, parser.input[parser.input_pos:])
+	parser.input_pos += n
+	return n, nil
+}
+
+// Reader read handler.
+func yaml_reader_read_handler(parser *yaml_parser_t, buffer []byte) (n int, err error) {
+	return parser.input_reader.Read(buffer)
+}
+
+// Set a string input.
+func yaml_parser_set_input_string(parser *yaml_parser_t, input []byte) {
+	if parser.read_handler != nil {
+		panic("must set the input source only once")
+	}
+	parser.read_handler = yaml_string_read_handler
+	parser.input = input
+	parser.input_pos = 0
+}
+
+// Set a file input.
+func yaml_parser_set_input_reader(parser *yaml_parser_t, r io.Reader) {
+	if parser.read_handler != nil {
+		panic("must set the input source only once")
+	}
+	parser.read_handler = yaml_reader_read_handler
+	parser.input_reader = r
+}
+
+// Set the source encoding.
+func yaml_parser_set_encoding(parser *yaml_parser_t, encoding yaml_encoding_t) {
+	if parser.encoding != yaml_ANY_ENCODING {
+		panic("must set the encoding only once")
+	}
+	parser.encoding = encoding
+}
+
+// Create a new emitter object.
+func yaml_emitter_initialize(emitter *yaml_emitter_t) {
+	*emitter = yaml_emitter_t{
+		buffer:     make([]byte, output_buffer_size),
+		raw_buffer: make([]byte, 0, output_raw_buffer_size),
+		states:     make([]yaml_emitter_state_t, 0, initial_stack_size),
+		events:     make([]yaml_event_t, 0, initial_queue_size),
+	}
+}
+
+// Destroy an emitter object.
+func yaml_emitter_delete(emitter *yaml_emitter_t) {
+	*emitter = yaml_emitter_t{}
+}
+
+// String write handler.
+func yaml_string_write_handler(emitter *yaml_emitter_t, buffer []byte) error {
+	*emitter.output_buffer = append(*emitter.output_buffer, buffer...)
+	return nil
+}
+
+// yaml_writer_write_handler uses emitter.output_writer to write the
+// emitted text.
+func yaml_writer_write_handler(emitter *yaml_emitter_t, buffer []byte) error {
+	_, err := emitter.output_writer.Write(buffer)
+	return err
+}
+
+// Set a string output.
+func yaml_emitter_set_output_string(emitter *yaml_emitter_t, output_buffer *[]byte) {
+	if emitter.write_handler != nil {
+		panic("must set the output target only once")
+	}
+	emitter.write_handler = yaml_string_write_handler
+	emitter.output_buffer = output_buffer
+}
+
+// Set a file output.
+func yaml_emitter_set_output_writer(emitter *yaml_emitter_t, w io.Writer) {
+	if emitter.write_handler != nil {
+		panic("must set the output target only once")
+	}
+	emitter.write_handler = yaml_writer_write_handler
+	emitter.output_writer = w
+}
+
+// Set the output encoding.
+func yaml_emitter_set_encoding(emitter *yaml_emitter_t, encoding yaml_encoding_t) {
+	if emitter.encoding != yaml_ANY_ENCODING {
+		panic("must set the output encoding only once")
+	}
+	emitter.encoding = encoding
+}
+
+// Set the canonical output style.
+func yaml_emitter_set_canonical(emitter *yaml_emitter_t, canonical bool) {
+	emitter.canonical = canonical
+}
+
+//// Set the indentation increment.
+func yaml_emitter_set_indent(emitter *yaml_emitter_t, indent int) {
+	if indent < 2 || indent > 9 {
+		indent = 2
+	}
+	emitter.best_indent = indent
+}
+
+// Set the preferred line width.
+func yaml_emitter_set_width(emitter *yaml_emitter_t, width int) {
+	if width < 0 {
+		width = -1
+	}
+	emitter.best_width = width
+}
+
+// Set if unescaped non-ASCII characters are allowed.
+func yaml_emitter_set_unicode(emitter *yaml_emitter_t, unicode bool) {
+	emitter.unicode = unicode
+}
+
+// Set the preferred line break character.
+func yaml_emitter_set_break(emitter *yaml_emitter_t, line_break yaml_break_t) {
+	emitter.line_break = line_break
+}
+
+///*
+// * Destroy a token object.
+// */
+//
+//YAML_DECLARE(void)
+//yaml_token_delete(yaml_token_t *token)
+//{
+//    assert(token);  // Non-NULL token object expected.
+//
+//    switch (token.type)
+//    {
+//        case YAML_TAG_DIRECTIVE_TOKEN:
+//            yaml_free(token.data.tag_directive.handle);
+//            yaml_free(token.data.tag_directive.prefix);
+//            break;
+//
+//        case YAML_ALIAS_TOKEN:
+//            yaml_free(token.data.alias.value);
+//            break;
+//
+//        case YAML_ANCHOR_TOKEN:
+//            yaml_free(token.data.anchor.value);
+//            break;
+//
+//        case YAML_TAG_TOKEN:
+//            yaml_free(token.data.tag.handle);
+//            yaml_free(token.data.tag.suffix);
+//            break;
+//
+//        case YAML_SCALAR_TOKEN:
+//            yaml_free(token.data.scalar.value);
+//            break;
+//
+//        default:
+//            break;
+//    }
+//
+//    memset(token, 0, sizeof(yaml_token_t));
+//}
+//
+///*
+// * Check if a string is a valid UTF-8 sequence.
+// *
+// * Check 'reader.c' for more details on UTF-8 encoding.
+// */
+//
+//static int
+//yaml_check_utf8(yaml_char_t *start, size_t length)
+//{
+//    yaml_char_t *end = start+length;
+//    yaml_char_t *pointer = start;
+//
+//    while (pointer < end) {
+//        unsigned char octet;
+//        unsigned int width;
+//        unsigned int value;
+//        size_t k;
+//
+//        octet = pointer[0];
+//        width = (octet & 0x80) == 0x00 ? 1 :
+//                (octet & 0xE0) == 0xC0 ? 2 :
+//                (octet & 0xF0) == 0xE0 ? 3 :
+//                (octet & 0xF8) == 0xF0 ? 4 : 0;
+//        value = (octet & 0x80) == 0x00 ? octet & 0x7F :
+//                (octet & 0xE0) == 0xC0 ? octet & 0x1F :
+//                (octet & 0xF0) == 0xE0 ? octet & 0x0F :
+//                (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0;
+//        if (!width) return 0;
+//        if (pointer+width > end) return 0;
+//        for (k = 1; k < width; k ++) {
+//            octet = pointer[k];
+//            if ((octet & 0xC0) != 0x80) return 0;
+//            value = (value << 6) + (octet & 0x3F);
+//        }
+//        if (!((width == 1) ||
+//            (width == 2 && value >= 0x80) ||
+//            (width == 3 && value >= 0x800) ||
+//            (width == 4 && value >= 0x10000))) return 0;
+//
+//        pointer += width;
+//    }
+//
+//    return 1;
+//}
+//
+
+// Create STREAM-START.
+func yaml_stream_start_event_initialize(event *yaml_event_t, encoding yaml_encoding_t) {
+	*event = yaml_event_t{
+		typ:      yaml_STREAM_START_EVENT,
+		encoding: encoding,
+	}
+}
+
+// Create STREAM-END.
+func yaml_stream_end_event_initialize(event *yaml_event_t) {
+	*event = yaml_event_t{
+		typ: yaml_STREAM_END_EVENT,
+	}
+}
+
+// Create DOCUMENT-START.
+func yaml_document_start_event_initialize(
+	event *yaml_event_t,
+	version_directive *yaml_version_directive_t,
+	tag_directives []yaml_tag_directive_t,
+	implicit bool,
+) {
+	*event = yaml_event_t{
+		typ:               yaml_DOCUMENT_START_EVENT,
+		version_directive: version_directive,
+		tag_directives:    tag_directives,
+		implicit:          implicit,
+	}
+}
+
+// Create DOCUMENT-END.
+func yaml_document_end_event_initialize(event *yaml_event_t, implicit bool) {
+	*event = yaml_event_t{
+		typ:      yaml_DOCUMENT_END_EVENT,
+		implicit: implicit,
+	}
+}
+
+///*
+// * Create ALIAS.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_alias_event_initialize(event *yaml_event_t, anchor *yaml_char_t)
+//{
+//    mark yaml_mark_t = { 0, 0, 0 }
+//    anchor_copy *yaml_char_t = NULL
+//
+//    assert(event) // Non-NULL event object is expected.
+//    assert(anchor) // Non-NULL anchor is expected.
+//
+//    if (!yaml_check_utf8(anchor, strlen((char *)anchor))) return 0
+//
+//    anchor_copy = yaml_strdup(anchor)
+//    if (!anchor_copy)
+//        return 0
+//
+//    ALIAS_EVENT_INIT(*event, anchor_copy, mark, mark)
+//
+//    return 1
+//}
+
+// Create SCALAR.
+func yaml_scalar_event_initialize(event *yaml_event_t, anchor, tag, value []byte, plain_implicit, quoted_implicit bool, style yaml_scalar_style_t) bool {
+	*event = yaml_event_t{
+		typ:             yaml_SCALAR_EVENT,
+		anchor:          anchor,
+		tag:             tag,
+		value:           value,
+		implicit:        plain_implicit,
+		quoted_implicit: quoted_implicit,
+		style:           yaml_style_t(style),
+	}
+	return true
+}
+
+// Create SEQUENCE-START.
+func yaml_sequence_start_event_initialize(event *yaml_event_t, anchor, tag []byte, implicit bool, style yaml_sequence_style_t) bool {
+	*event = yaml_event_t{
+		typ:      yaml_SEQUENCE_START_EVENT,
+		anchor:   anchor,
+		tag:      tag,
+		implicit: implicit,
+		style:    yaml_style_t(style),
+	}
+	return true
+}
+
+// Create SEQUENCE-END.
+func yaml_sequence_end_event_initialize(event *yaml_event_t) bool {
+	*event = yaml_event_t{
+		typ: yaml_SEQUENCE_END_EVENT,
+	}
+	return true
+}
+
+// Create MAPPING-START.
+func yaml_mapping_start_event_initialize(event *yaml_event_t, anchor, tag []byte, implicit bool, style yaml_mapping_style_t) {
+	*event = yaml_event_t{
+		typ:      yaml_MAPPING_START_EVENT,
+		anchor:   anchor,
+		tag:      tag,
+		implicit: implicit,
+		style:    yaml_style_t(style),
+	}
+}
+
+// Create MAPPING-END.
+func yaml_mapping_end_event_initialize(event *yaml_event_t) {
+	*event = yaml_event_t{
+		typ: yaml_MAPPING_END_EVENT,
+	}
+}
+
+// Destroy an event object.
+func yaml_event_delete(event *yaml_event_t) {
+	*event = yaml_event_t{}
+}
+
+///*
+// * Create a document object.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_document_initialize(document *yaml_document_t,
+//        version_directive *yaml_version_directive_t,
+//        tag_directives_start *yaml_tag_directive_t,
+//        tag_directives_end *yaml_tag_directive_t,
+//        start_implicit int, end_implicit int)
+//{
+//    struct {
+//        error yaml_error_type_t
+//    } context
+//    struct {
+//        start *yaml_node_t
+//        end *yaml_node_t
+//        top *yaml_node_t
+//    } nodes = { NULL, NULL, NULL }
+//    version_directive_copy *yaml_version_directive_t = NULL
+//    struct {
+//        start *yaml_tag_directive_t
+//        end *yaml_tag_directive_t
+//        top *yaml_tag_directive_t
+//    } tag_directives_copy = { NULL, NULL, NULL }
+//    value yaml_tag_directive_t = { NULL, NULL }
+//    mark yaml_mark_t = { 0, 0, 0 }
+//
+//    assert(document) // Non-NULL document object is expected.
+//    assert((tag_directives_start && tag_directives_end) ||
+//            (tag_directives_start == tag_directives_end))
+//                            // Valid tag directives are expected.
+//
+//    if (!STACK_INIT(&context, nodes, INITIAL_STACK_SIZE)) goto error
+//
+//    if (version_directive) {
+//        version_directive_copy = yaml_malloc(sizeof(yaml_version_directive_t))
+//        if (!version_directive_copy) goto error
+//        version_directive_copy.major = version_directive.major
+//        version_directive_copy.minor = version_directive.minor
+//    }
+//
+//    if (tag_directives_start != tag_directives_end) {
+//        tag_directive *yaml_tag_directive_t
+//        if (!STACK_INIT(&context, tag_directives_copy, INITIAL_STACK_SIZE))
+//            goto error
+//        for (tag_directive = tag_directives_start
+//                tag_directive != tag_directives_end; tag_directive ++) {
+//            assert(tag_directive.handle)
+//            assert(tag_directive.prefix)
+//            if (!yaml_check_utf8(tag_directive.handle,
+//                        strlen((char *)tag_directive.handle)))
+//                goto error
+//            if (!yaml_check_utf8(tag_directive.prefix,
+//                        strlen((char *)tag_directive.prefix)))
+//                goto error
+//            value.handle = yaml_strdup(tag_directive.handle)
+//            value.prefix = yaml_strdup(tag_directive.prefix)
+//            if (!value.handle || !value.prefix) goto error
+//            if (!PUSH(&context, tag_directives_copy, value))
+//                goto error
+//            value.handle = NULL
+//            value.prefix = NULL
+//        }
+//    }
+//
+//    DOCUMENT_INIT(*document, nodes.start, nodes.end, version_directive_copy,
+//            tag_directives_copy.start, tag_directives_copy.top,
+//            start_implicit, end_implicit, mark, mark)
+//
+//    return 1
+//
+//error:
+//    STACK_DEL(&context, nodes)
+//    yaml_free(version_directive_copy)
+//    while (!STACK_EMPTY(&context, tag_directives_copy)) {
+//        value yaml_tag_directive_t = POP(&context, tag_directives_copy)
+//        yaml_free(value.handle)
+//        yaml_free(value.prefix)
+//    }
+//    STACK_DEL(&context, tag_directives_copy)
+//    yaml_free(value.handle)
+//    yaml_free(value.prefix)
+//
+//    return 0
+//}
+//
+///*
+// * Destroy a document object.
+// */
+//
+//YAML_DECLARE(void)
+//yaml_document_delete(document *yaml_document_t)
+//{
+//    struct {
+//        error yaml_error_type_t
+//    } context
+//    tag_directive *yaml_tag_directive_t
+//
+//    context.error = YAML_NO_ERROR // Eliminate a compiler warning.
+//
+//    assert(document) // Non-NULL document object is expected.
+//
+//    while (!STACK_EMPTY(&context, document.nodes)) {
+//        node yaml_node_t = POP(&context, document.nodes)
+//        yaml_free(node.tag)
+//        switch (node.type) {
+//            case YAML_SCALAR_NODE:
+//                yaml_free(node.data.scalar.value)
+//                break
+//            case YAML_SEQUENCE_NODE:
+//                STACK_DEL(&context, node.data.sequence.items)
+//                break
+//            case YAML_MAPPING_NODE:
+//                STACK_DEL(&context, node.data.mapping.pairs)
+//                break
+//            default:
+//                assert(0) // Should not happen.
+//        }
+//    }
+//    STACK_DEL(&context, document.nodes)
+//
+//    yaml_free(document.version_directive)
+//    for (tag_directive = document.tag_directives.start
+//            tag_directive != document.tag_directives.end
+//            tag_directive++) {
+//        yaml_free(tag_directive.handle)
+//        yaml_free(tag_directive.prefix)
+//    }
+//    yaml_free(document.tag_directives.start)
+//
+//    memset(document, 0, sizeof(yaml_document_t))
+//}
+//
+///**
+// * Get a document node.
+// */
+//
+//YAML_DECLARE(yaml_node_t *)
+//yaml_document_get_node(document *yaml_document_t, index int)
+//{
+//    assert(document) // Non-NULL document object is expected.
+//
+//    if (index > 0 && document.nodes.start + index <= document.nodes.top) {
+//        return document.nodes.start + index - 1
+//    }
+//    return NULL
+//}
+//
+///**
+// * Get the root object.
+// */
+//
+//YAML_DECLARE(yaml_node_t *)
+//yaml_document_get_root_node(document *yaml_document_t)
+//{
+//    assert(document) // Non-NULL document object is expected.
+//
+//    if (document.nodes.top != document.nodes.start) {
+//        return document.nodes.start
+//    }
+//    return NULL
+//}
+//
+///*
+// * Add a scalar node to a document.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_document_add_scalar(document *yaml_document_t,
+//        tag *yaml_char_t, value *yaml_char_t, length int,
+//        style yaml_scalar_style_t)
+//{
+//    struct {
+//        error yaml_error_type_t
+//    } context
+//    mark yaml_mark_t = { 0, 0, 0 }
+//    tag_copy *yaml_char_t = NULL
+//    value_copy *yaml_char_t = NULL
+//    node yaml_node_t
+//
+//    assert(document) // Non-NULL document object is expected.
+//    assert(value) // Non-NULL value is expected.
+//
+//    if (!tag) {
+//        tag = (yaml_char_t *)YAML_DEFAULT_SCALAR_TAG
+//    }
+//
+//    if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error
+//    tag_copy = yaml_strdup(tag)
+//    if (!tag_copy) goto error
+//
+//    if (length < 0) {
+//        length = strlen((char *)value)
+//    }
+//
+//    if (!yaml_check_utf8(value, length)) goto error
+//    value_copy = yaml_malloc(length+1)
+//    if (!value_copy) goto error
+//    memcpy(value_copy, value, length)
+//    value_copy[length] = '\0'
+//
+//    SCALAR_NODE_INIT(node, tag_copy, value_copy, length, style, mark, mark)
+//    if (!PUSH(&context, document.nodes, node)) goto error
+//
+//    return document.nodes.top - document.nodes.start
+//
+//error:
+//    yaml_free(tag_copy)
+//    yaml_free(value_copy)
+//
+//    return 0
+//}
+//
+///*
+// * Add a sequence node to a document.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_document_add_sequence(document *yaml_document_t,
+//        tag *yaml_char_t, style yaml_sequence_style_t)
+//{
+//    struct {
+//        error yaml_error_type_t
+//    } context
+//    mark yaml_mark_t = { 0, 0, 0 }
+//    tag_copy *yaml_char_t = NULL
+//    struct {
+//        start *yaml_node_item_t
+//        end *yaml_node_item_t
+//        top *yaml_node_item_t
+//    } items = { NULL, NULL, NULL }
+//    node yaml_node_t
+//
+//    assert(document) // Non-NULL document object is expected.
+//
+//    if (!tag) {
+//        tag = (yaml_char_t *)YAML_DEFAULT_SEQUENCE_TAG
+//    }
+//
+//    if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error
+//    tag_copy = yaml_strdup(tag)
+//    if (!tag_copy) goto error
+//
+//    if (!STACK_INIT(&context, items, INITIAL_STACK_SIZE)) goto error
+//
+//    SEQUENCE_NODE_INIT(node, tag_copy, items.start, items.end,
+//            style, mark, mark)
+//    if (!PUSH(&context, document.nodes, node)) goto error
+//
+//    return document.nodes.top - document.nodes.start
+//
+//error:
+//    STACK_DEL(&context, items)
+//    yaml_free(tag_copy)
+//
+//    return 0
+//}
+//
+///*
+// * Add a mapping node to a document.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_document_add_mapping(document *yaml_document_t,
+//        tag *yaml_char_t, style yaml_mapping_style_t)
+//{
+//    struct {
+//        error yaml_error_type_t
+//    } context
+//    mark yaml_mark_t = { 0, 0, 0 }
+//    tag_copy *yaml_char_t = NULL
+//    struct {
+//        start *yaml_node_pair_t
+//        end *yaml_node_pair_t
+//        top *yaml_node_pair_t
+//    } pairs = { NULL, NULL, NULL }
+//    node yaml_node_t
+//
+//    assert(document) // Non-NULL document object is expected.
+//
+//    if (!tag) {
+//        tag = (yaml_char_t *)YAML_DEFAULT_MAPPING_TAG
+//    }
+//
+//    if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error
+//    tag_copy = yaml_strdup(tag)
+//    if (!tag_copy) goto error
+//
+//    if (!STACK_INIT(&context, pairs, INITIAL_STACK_SIZE)) goto error
+//
+//    MAPPING_NODE_INIT(node, tag_copy, pairs.start, pairs.end,
+//            style, mark, mark)
+//    if (!PUSH(&context, document.nodes, node)) goto error
+//
+//    return document.nodes.top - document.nodes.start
+//
+//error:
+//    STACK_DEL(&context, pairs)
+//    yaml_free(tag_copy)
+//
+//    return 0
+//}
+//
+///*
+// * Append an item to a sequence node.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_document_append_sequence_item(document *yaml_document_t,
+//        sequence int, item int)
+//{
+//    struct {
+//        error yaml_error_type_t
+//    } context
+//
+//    assert(document) // Non-NULL document is required.
+//    assert(sequence > 0
+//            && document.nodes.start + sequence <= document.nodes.top)
+//                            // Valid sequence id is required.
+//    assert(document.nodes.start[sequence-1].type == YAML_SEQUENCE_NODE)
+//                            // A sequence node is required.
+//    assert(item > 0 && document.nodes.start + item <= document.nodes.top)
+//                            // Valid item id is required.
+//
+//    if (!PUSH(&context,
+//                document.nodes.start[sequence-1].data.sequence.items, item))
+//        return 0
+//
+//    return 1
+//}
+//
+///*
+// * Append a pair of a key and a value to a mapping node.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_document_append_mapping_pair(document *yaml_document_t,
+//        mapping int, key int, value int)
+//{
+//    struct {
+//        error yaml_error_type_t
+//    } context
+//
+//    pair yaml_node_pair_t
+//
+//    assert(document) // Non-NULL document is required.
+//    assert(mapping > 0
+//            && document.nodes.start + mapping <= document.nodes.top)
+//                            // Valid mapping id is required.
+//    assert(document.nodes.start[mapping-1].type == YAML_MAPPING_NODE)
+//                            // A mapping node is required.
+//    assert(key > 0 && document.nodes.start + key <= document.nodes.top)
+//                            // Valid key id is required.
+//    assert(value > 0 && document.nodes.start + value <= document.nodes.top)
+//                            // Valid value id is required.
+//
+//    pair.key = key
+//    pair.value = value
+//
+//    if (!PUSH(&context,
+//                document.nodes.start[mapping-1].data.mapping.pairs, pair))
+//        return 0
+//
+//    return 1
+//}
+//
+//

+ 775 - 0
vendor/gopkg.in/yaml.v2/decode.go

@@ -0,0 +1,775 @@
+package yaml
+
+import (
+	"encoding"
+	"encoding/base64"
+	"fmt"
+	"io"
+	"math"
+	"reflect"
+	"strconv"
+	"time"
+)
+
+const (
+	documentNode = 1 << iota
+	mappingNode
+	sequenceNode
+	scalarNode
+	aliasNode
+)
+
+type node struct {
+	kind         int
+	line, column int
+	tag          string
+	// For an alias node, alias holds the resolved alias.
+	alias    *node
+	value    string
+	implicit bool
+	children []*node
+	anchors  map[string]*node
+}
+
+// ----------------------------------------------------------------------------
+// Parser, produces a node tree out of a libyaml event stream.
+
+type parser struct {
+	parser   yaml_parser_t
+	event    yaml_event_t
+	doc      *node
+	doneInit bool
+}
+
+func newParser(b []byte) *parser {
+	p := parser{}
+	if !yaml_parser_initialize(&p.parser) {
+		panic("failed to initialize YAML emitter")
+	}
+	if len(b) == 0 {
+		b = []byte{'\n'}
+	}
+	yaml_parser_set_input_string(&p.parser, b)
+	return &p
+}
+
+func newParserFromReader(r io.Reader) *parser {
+	p := parser{}
+	if !yaml_parser_initialize(&p.parser) {
+		panic("failed to initialize YAML emitter")
+	}
+	yaml_parser_set_input_reader(&p.parser, r)
+	return &p
+}
+
+func (p *parser) init() {
+	if p.doneInit {
+		return
+	}
+	p.expect(yaml_STREAM_START_EVENT)
+	p.doneInit = true
+}
+
+func (p *parser) destroy() {
+	if p.event.typ != yaml_NO_EVENT {
+		yaml_event_delete(&p.event)
+	}
+	yaml_parser_delete(&p.parser)
+}
+
+// expect consumes an event from the event stream and
+// checks that it's of the expected type.
+func (p *parser) expect(e yaml_event_type_t) {
+	if p.event.typ == yaml_NO_EVENT {
+		if !yaml_parser_parse(&p.parser, &p.event) {
+			p.fail()
+		}
+	}
+	if p.event.typ == yaml_STREAM_END_EVENT {
+		failf("attempted to go past the end of stream; corrupted value?")
+	}
+	if p.event.typ != e {
+		p.parser.problem = fmt.Sprintf("expected %s event but got %s", e, p.event.typ)
+		p.fail()
+	}
+	yaml_event_delete(&p.event)
+	p.event.typ = yaml_NO_EVENT
+}
+
+// peek peeks at the next event in the event stream,
+// puts the results into p.event and returns the event type.
+func (p *parser) peek() yaml_event_type_t {
+	if p.event.typ != yaml_NO_EVENT {
+		return p.event.typ
+	}
+	if !yaml_parser_parse(&p.parser, &p.event) {
+		p.fail()
+	}
+	return p.event.typ
+}
+
+func (p *parser) fail() {
+	var where string
+	var line int
+	if p.parser.problem_mark.line != 0 {
+		line = p.parser.problem_mark.line
+		// Scanner errors don't iterate line before returning error
+		if p.parser.error == yaml_SCANNER_ERROR {
+			line++
+		}
+	} else if p.parser.context_mark.line != 0 {
+		line = p.parser.context_mark.line
+	}
+	if line != 0 {
+		where = "line " + strconv.Itoa(line) + ": "
+	}
+	var msg string
+	if len(p.parser.problem) > 0 {
+		msg = p.parser.problem
+	} else {
+		msg = "unknown problem parsing YAML content"
+	}
+	failf("%s%s", where, msg)
+}
+
+func (p *parser) anchor(n *node, anchor []byte) {
+	if anchor != nil {
+		p.doc.anchors[string(anchor)] = n
+	}
+}
+
+func (p *parser) parse() *node {
+	p.init()
+	switch p.peek() {
+	case yaml_SCALAR_EVENT:
+		return p.scalar()
+	case yaml_ALIAS_EVENT:
+		return p.alias()
+	case yaml_MAPPING_START_EVENT:
+		return p.mapping()
+	case yaml_SEQUENCE_START_EVENT:
+		return p.sequence()
+	case yaml_DOCUMENT_START_EVENT:
+		return p.document()
+	case yaml_STREAM_END_EVENT:
+		// Happens when attempting to decode an empty buffer.
+		return nil
+	default:
+		panic("attempted to parse unknown event: " + p.event.typ.String())
+	}
+}
+
+func (p *parser) node(kind int) *node {
+	return &node{
+		kind:   kind,
+		line:   p.event.start_mark.line,
+		column: p.event.start_mark.column,
+	}
+}
+
+func (p *parser) document() *node {
+	n := p.node(documentNode)
+	n.anchors = make(map[string]*node)
+	p.doc = n
+	p.expect(yaml_DOCUMENT_START_EVENT)
+	n.children = append(n.children, p.parse())
+	p.expect(yaml_DOCUMENT_END_EVENT)
+	return n
+}
+
+func (p *parser) alias() *node {
+	n := p.node(aliasNode)
+	n.value = string(p.event.anchor)
+	n.alias = p.doc.anchors[n.value]
+	if n.alias == nil {
+		failf("unknown anchor '%s' referenced", n.value)
+	}
+	p.expect(yaml_ALIAS_EVENT)
+	return n
+}
+
+func (p *parser) scalar() *node {
+	n := p.node(scalarNode)
+	n.value = string(p.event.value)
+	n.tag = string(p.event.tag)
+	n.implicit = p.event.implicit
+	p.anchor(n, p.event.anchor)
+	p.expect(yaml_SCALAR_EVENT)
+	return n
+}
+
+func (p *parser) sequence() *node {
+	n := p.node(sequenceNode)
+	p.anchor(n, p.event.anchor)
+	p.expect(yaml_SEQUENCE_START_EVENT)
+	for p.peek() != yaml_SEQUENCE_END_EVENT {
+		n.children = append(n.children, p.parse())
+	}
+	p.expect(yaml_SEQUENCE_END_EVENT)
+	return n
+}
+
+func (p *parser) mapping() *node {
+	n := p.node(mappingNode)
+	p.anchor(n, p.event.anchor)
+	p.expect(yaml_MAPPING_START_EVENT)
+	for p.peek() != yaml_MAPPING_END_EVENT {
+		n.children = append(n.children, p.parse(), p.parse())
+	}
+	p.expect(yaml_MAPPING_END_EVENT)
+	return n
+}
+
+// ----------------------------------------------------------------------------
+// Decoder, unmarshals a node into a provided value.
+
+type decoder struct {
+	doc     *node
+	aliases map[*node]bool
+	mapType reflect.Type
+	terrors []string
+	strict  bool
+}
+
+var (
+	mapItemType    = reflect.TypeOf(MapItem{})
+	durationType   = reflect.TypeOf(time.Duration(0))
+	defaultMapType = reflect.TypeOf(map[interface{}]interface{}{})
+	ifaceType      = defaultMapType.Elem()
+	timeType       = reflect.TypeOf(time.Time{})
+	ptrTimeType    = reflect.TypeOf(&time.Time{})
+)
+
+func newDecoder(strict bool) *decoder {
+	d := &decoder{mapType: defaultMapType, strict: strict}
+	d.aliases = make(map[*node]bool)
+	return d
+}
+
+func (d *decoder) terror(n *node, tag string, out reflect.Value) {
+	if n.tag != "" {
+		tag = n.tag
+	}
+	value := n.value
+	if tag != yaml_SEQ_TAG && tag != yaml_MAP_TAG {
+		if len(value) > 10 {
+			value = " `" + value[:7] + "...`"
+		} else {
+			value = " `" + value + "`"
+		}
+	}
+	d.terrors = append(d.terrors, fmt.Sprintf("line %d: cannot unmarshal %s%s into %s", n.line+1, shortTag(tag), value, out.Type()))
+}
+
+func (d *decoder) callUnmarshaler(n *node, u Unmarshaler) (good bool) {
+	terrlen := len(d.terrors)
+	err := u.UnmarshalYAML(func(v interface{}) (err error) {
+		defer handleErr(&err)
+		d.unmarshal(n, reflect.ValueOf(v))
+		if len(d.terrors) > terrlen {
+			issues := d.terrors[terrlen:]
+			d.terrors = d.terrors[:terrlen]
+			return &TypeError{issues}
+		}
+		return nil
+	})
+	if e, ok := err.(*TypeError); ok {
+		d.terrors = append(d.terrors, e.Errors...)
+		return false
+	}
+	if err != nil {
+		fail(err)
+	}
+	return true
+}
+
+// d.prepare initializes and dereferences pointers and calls UnmarshalYAML
+// if a value is found to implement it.
+// It returns the initialized and dereferenced out value, whether
+// unmarshalling was already done by UnmarshalYAML, and if so whether
+// its types unmarshalled appropriately.
+//
+// If n holds a null value, prepare returns before doing anything.
+func (d *decoder) prepare(n *node, out reflect.Value) (newout reflect.Value, unmarshaled, good bool) {
+	if n.tag == yaml_NULL_TAG || n.kind == scalarNode && n.tag == "" && (n.value == "null" || n.value == "~" || n.value == "" && n.implicit) {
+		return out, false, false
+	}
+	again := true
+	for again {
+		again = false
+		if out.Kind() == reflect.Ptr {
+			if out.IsNil() {
+				out.Set(reflect.New(out.Type().Elem()))
+			}
+			out = out.Elem()
+			again = true
+		}
+		if out.CanAddr() {
+			if u, ok := out.Addr().Interface().(Unmarshaler); ok {
+				good = d.callUnmarshaler(n, u)
+				return out, true, good
+			}
+		}
+	}
+	return out, false, false
+}
+
+func (d *decoder) unmarshal(n *node, out reflect.Value) (good bool) {
+	switch n.kind {
+	case documentNode:
+		return d.document(n, out)
+	case aliasNode:
+		return d.alias(n, out)
+	}
+	out, unmarshaled, good := d.prepare(n, out)
+	if unmarshaled {
+		return good
+	}
+	switch n.kind {
+	case scalarNode:
+		good = d.scalar(n, out)
+	case mappingNode:
+		good = d.mapping(n, out)
+	case sequenceNode:
+		good = d.sequence(n, out)
+	default:
+		panic("internal error: unknown node kind: " + strconv.Itoa(n.kind))
+	}
+	return good
+}
+
+func (d *decoder) document(n *node, out reflect.Value) (good bool) {
+	if len(n.children) == 1 {
+		d.doc = n
+		d.unmarshal(n.children[0], out)
+		return true
+	}
+	return false
+}
+
+func (d *decoder) alias(n *node, out reflect.Value) (good bool) {
+	if d.aliases[n] {
+		// TODO this could actually be allowed in some circumstances.
+		failf("anchor '%s' value contains itself", n.value)
+	}
+	d.aliases[n] = true
+	good = d.unmarshal(n.alias, out)
+	delete(d.aliases, n)
+	return good
+}
+
+var zeroValue reflect.Value
+
+func resetMap(out reflect.Value) {
+	for _, k := range out.MapKeys() {
+		out.SetMapIndex(k, zeroValue)
+	}
+}
+
+func (d *decoder) scalar(n *node, out reflect.Value) bool {
+	var tag string
+	var resolved interface{}
+	if n.tag == "" && !n.implicit {
+		tag = yaml_STR_TAG
+		resolved = n.value
+	} else {
+		tag, resolved = resolve(n.tag, n.value)
+		if tag == yaml_BINARY_TAG {
+			data, err := base64.StdEncoding.DecodeString(resolved.(string))
+			if err != nil {
+				failf("!!binary value contains invalid base64 data")
+			}
+			resolved = string(data)
+		}
+	}
+	if resolved == nil {
+		if out.Kind() == reflect.Map && !out.CanAddr() {
+			resetMap(out)
+		} else {
+			out.Set(reflect.Zero(out.Type()))
+		}
+		return true
+	}
+	if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() {
+		// We've resolved to exactly the type we want, so use that.
+		out.Set(resolvedv)
+		return true
+	}
+	// Perhaps we can use the value as a TextUnmarshaler to
+	// set its value.
+	if out.CanAddr() {
+		u, ok := out.Addr().Interface().(encoding.TextUnmarshaler)
+		if ok {
+			var text []byte
+			if tag == yaml_BINARY_TAG {
+				text = []byte(resolved.(string))
+			} else {
+				// We let any value be unmarshaled into TextUnmarshaler.
+				// That might be more lax than we'd like, but the
+				// TextUnmarshaler itself should bowl out any dubious values.
+				text = []byte(n.value)
+			}
+			err := u.UnmarshalText(text)
+			if err != nil {
+				fail(err)
+			}
+			return true
+		}
+	}
+	switch out.Kind() {
+	case reflect.String:
+		if tag == yaml_BINARY_TAG {
+			out.SetString(resolved.(string))
+			return true
+		}
+		if resolved != nil {
+			out.SetString(n.value)
+			return true
+		}
+	case reflect.Interface:
+		if resolved == nil {
+			out.Set(reflect.Zero(out.Type()))
+		} else if tag == yaml_TIMESTAMP_TAG {
+			// It looks like a timestamp but for backward compatibility
+			// reasons we set it as a string, so that code that unmarshals
+			// timestamp-like values into interface{} will continue to
+			// see a string and not a time.Time.
+			// TODO(v3) Drop this.
+			out.Set(reflect.ValueOf(n.value))
+		} else {
+			out.Set(reflect.ValueOf(resolved))
+		}
+		return true
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		switch resolved := resolved.(type) {
+		case int:
+			if !out.OverflowInt(int64(resolved)) {
+				out.SetInt(int64(resolved))
+				return true
+			}
+		case int64:
+			if !out.OverflowInt(resolved) {
+				out.SetInt(resolved)
+				return true
+			}
+		case uint64:
+			if resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) {
+				out.SetInt(int64(resolved))
+				return true
+			}
+		case float64:
+			if resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) {
+				out.SetInt(int64(resolved))
+				return true
+			}
+		case string:
+			if out.Type() == durationType {
+				d, err := time.ParseDuration(resolved)
+				if err == nil {
+					out.SetInt(int64(d))
+					return true
+				}
+			}
+		}
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+		switch resolved := resolved.(type) {
+		case int:
+			if resolved >= 0 && !out.OverflowUint(uint64(resolved)) {
+				out.SetUint(uint64(resolved))
+				return true
+			}
+		case int64:
+			if resolved >= 0 && !out.OverflowUint(uint64(resolved)) {
+				out.SetUint(uint64(resolved))
+				return true
+			}
+		case uint64:
+			if !out.OverflowUint(uint64(resolved)) {
+				out.SetUint(uint64(resolved))
+				return true
+			}
+		case float64:
+			if resolved <= math.MaxUint64 && !out.OverflowUint(uint64(resolved)) {
+				out.SetUint(uint64(resolved))
+				return true
+			}
+		}
+	case reflect.Bool:
+		switch resolved := resolved.(type) {
+		case bool:
+			out.SetBool(resolved)
+			return true
+		}
+	case reflect.Float32, reflect.Float64:
+		switch resolved := resolved.(type) {
+		case int:
+			out.SetFloat(float64(resolved))
+			return true
+		case int64:
+			out.SetFloat(float64(resolved))
+			return true
+		case uint64:
+			out.SetFloat(float64(resolved))
+			return true
+		case float64:
+			out.SetFloat(resolved)
+			return true
+		}
+	case reflect.Struct:
+		if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() {
+			out.Set(resolvedv)
+			return true
+		}
+	case reflect.Ptr:
+		if out.Type().Elem() == reflect.TypeOf(resolved) {
+			// TODO DOes this make sense? When is out a Ptr except when decoding a nil value?
+			elem := reflect.New(out.Type().Elem())
+			elem.Elem().Set(reflect.ValueOf(resolved))
+			out.Set(elem)
+			return true
+		}
+	}
+	d.terror(n, tag, out)
+	return false
+}
+
+func settableValueOf(i interface{}) reflect.Value {
+	v := reflect.ValueOf(i)
+	sv := reflect.New(v.Type()).Elem()
+	sv.Set(v)
+	return sv
+}
+
+func (d *decoder) sequence(n *node, out reflect.Value) (good bool) {
+	l := len(n.children)
+
+	var iface reflect.Value
+	switch out.Kind() {
+	case reflect.Slice:
+		out.Set(reflect.MakeSlice(out.Type(), l, l))
+	case reflect.Array:
+		if l != out.Len() {
+			failf("invalid array: want %d elements but got %d", out.Len(), l)
+		}
+	case reflect.Interface:
+		// No type hints. Will have to use a generic sequence.
+		iface = out
+		out = settableValueOf(make([]interface{}, l))
+	default:
+		d.terror(n, yaml_SEQ_TAG, out)
+		return false
+	}
+	et := out.Type().Elem()
+
+	j := 0
+	for i := 0; i < l; i++ {
+		e := reflect.New(et).Elem()
+		if ok := d.unmarshal(n.children[i], e); ok {
+			out.Index(j).Set(e)
+			j++
+		}
+	}
+	if out.Kind() != reflect.Array {
+		out.Set(out.Slice(0, j))
+	}
+	if iface.IsValid() {
+		iface.Set(out)
+	}
+	return true
+}
+
+func (d *decoder) mapping(n *node, out reflect.Value) (good bool) {
+	switch out.Kind() {
+	case reflect.Struct:
+		return d.mappingStruct(n, out)
+	case reflect.Slice:
+		return d.mappingSlice(n, out)
+	case reflect.Map:
+		// okay
+	case reflect.Interface:
+		if d.mapType.Kind() == reflect.Map {
+			iface := out
+			out = reflect.MakeMap(d.mapType)
+			iface.Set(out)
+		} else {
+			slicev := reflect.New(d.mapType).Elem()
+			if !d.mappingSlice(n, slicev) {
+				return false
+			}
+			out.Set(slicev)
+			return true
+		}
+	default:
+		d.terror(n, yaml_MAP_TAG, out)
+		return false
+	}
+	outt := out.Type()
+	kt := outt.Key()
+	et := outt.Elem()
+
+	mapType := d.mapType
+	if outt.Key() == ifaceType && outt.Elem() == ifaceType {
+		d.mapType = outt
+	}
+
+	if out.IsNil() {
+		out.Set(reflect.MakeMap(outt))
+	}
+	l := len(n.children)
+	for i := 0; i < l; i += 2 {
+		if isMerge(n.children[i]) {
+			d.merge(n.children[i+1], out)
+			continue
+		}
+		k := reflect.New(kt).Elem()
+		if d.unmarshal(n.children[i], k) {
+			kkind := k.Kind()
+			if kkind == reflect.Interface {
+				kkind = k.Elem().Kind()
+			}
+			if kkind == reflect.Map || kkind == reflect.Slice {
+				failf("invalid map key: %#v", k.Interface())
+			}
+			e := reflect.New(et).Elem()
+			if d.unmarshal(n.children[i+1], e) {
+				d.setMapIndex(n.children[i+1], out, k, e)
+			}
+		}
+	}
+	d.mapType = mapType
+	return true
+}
+
+func (d *decoder) setMapIndex(n *node, out, k, v reflect.Value) {
+	if d.strict && out.MapIndex(k) != zeroValue {
+		d.terrors = append(d.terrors, fmt.Sprintf("line %d: key %#v already set in map", n.line+1, k.Interface()))
+		return
+	}
+	out.SetMapIndex(k, v)
+}
+
+func (d *decoder) mappingSlice(n *node, out reflect.Value) (good bool) {
+	outt := out.Type()
+	if outt.Elem() != mapItemType {
+		d.terror(n, yaml_MAP_TAG, out)
+		return false
+	}
+
+	mapType := d.mapType
+	d.mapType = outt
+
+	var slice []MapItem
+	var l = len(n.children)
+	for i := 0; i < l; i += 2 {
+		if isMerge(n.children[i]) {
+			d.merge(n.children[i+1], out)
+			continue
+		}
+		item := MapItem{}
+		k := reflect.ValueOf(&item.Key).Elem()
+		if d.unmarshal(n.children[i], k) {
+			v := reflect.ValueOf(&item.Value).Elem()
+			if d.unmarshal(n.children[i+1], v) {
+				slice = append(slice, item)
+			}
+		}
+	}
+	out.Set(reflect.ValueOf(slice))
+	d.mapType = mapType
+	return true
+}
+
+func (d *decoder) mappingStruct(n *node, out reflect.Value) (good bool) {
+	sinfo, err := getStructInfo(out.Type())
+	if err != nil {
+		panic(err)
+	}
+	name := settableValueOf("")
+	l := len(n.children)
+
+	var inlineMap reflect.Value
+	var elemType reflect.Type
+	if sinfo.InlineMap != -1 {
+		inlineMap = out.Field(sinfo.InlineMap)
+		inlineMap.Set(reflect.New(inlineMap.Type()).Elem())
+		elemType = inlineMap.Type().Elem()
+	}
+
+	var doneFields []bool
+	if d.strict {
+		doneFields = make([]bool, len(sinfo.FieldsList))
+	}
+	for i := 0; i < l; i += 2 {
+		ni := n.children[i]
+		if isMerge(ni) {
+			d.merge(n.children[i+1], out)
+			continue
+		}
+		if !d.unmarshal(ni, name) {
+			continue
+		}
+		if info, ok := sinfo.FieldsMap[name.String()]; ok {
+			if d.strict {
+				if doneFields[info.Id] {
+					d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s already set in type %s", ni.line+1, name.String(), out.Type()))
+					continue
+				}
+				doneFields[info.Id] = true
+			}
+			var field reflect.Value
+			if info.Inline == nil {
+				field = out.Field(info.Num)
+			} else {
+				field = out.FieldByIndex(info.Inline)
+			}
+			d.unmarshal(n.children[i+1], field)
+		} else if sinfo.InlineMap != -1 {
+			if inlineMap.IsNil() {
+				inlineMap.Set(reflect.MakeMap(inlineMap.Type()))
+			}
+			value := reflect.New(elemType).Elem()
+			d.unmarshal(n.children[i+1], value)
+			d.setMapIndex(n.children[i+1], inlineMap, name, value)
+		} else if d.strict {
+			d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s not found in type %s", ni.line+1, name.String(), out.Type()))
+		}
+	}
+	return true
+}
+
+func failWantMap() {
+	failf("map merge requires map or sequence of maps as the value")
+}
+
+func (d *decoder) merge(n *node, out reflect.Value) {
+	switch n.kind {
+	case mappingNode:
+		d.unmarshal(n, out)
+	case aliasNode:
+		an, ok := d.doc.anchors[n.value]
+		if ok && an.kind != mappingNode {
+			failWantMap()
+		}
+		d.unmarshal(n, out)
+	case sequenceNode:
+		// Step backwards as earlier nodes take precedence.
+		for i := len(n.children) - 1; i >= 0; i-- {
+			ni := n.children[i]
+			if ni.kind == aliasNode {
+				an, ok := d.doc.anchors[ni.value]
+				if ok && an.kind != mappingNode {
+					failWantMap()
+				}
+			} else if ni.kind != mappingNode {
+				failWantMap()
+			}
+			d.unmarshal(ni, out)
+		}
+	default:
+		failWantMap()
+	}
+}
+
+func isMerge(n *node) bool {
+	return n.kind == scalarNode && n.value == "<<" && (n.implicit == true || n.tag == yaml_MERGE_TAG)
+}

+ 1685 - 0
vendor/gopkg.in/yaml.v2/emitterc.go

@@ -0,0 +1,1685 @@
+package yaml
+
+import (
+	"bytes"
+	"fmt"
+)
+
+// Flush the buffer if needed.
+func flush(emitter *yaml_emitter_t) bool {
+	if emitter.buffer_pos+5 >= len(emitter.buffer) {
+		return yaml_emitter_flush(emitter)
+	}
+	return true
+}
+
+// Put a character to the output buffer.
+func put(emitter *yaml_emitter_t, value byte) bool {
+	if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) {
+		return false
+	}
+	emitter.buffer[emitter.buffer_pos] = value
+	emitter.buffer_pos++
+	emitter.column++
+	return true
+}
+
+// Put a line break to the output buffer.
+func put_break(emitter *yaml_emitter_t) bool {
+	if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) {
+		return false
+	}
+	switch emitter.line_break {
+	case yaml_CR_BREAK:
+		emitter.buffer[emitter.buffer_pos] = '\r'
+		emitter.buffer_pos += 1
+	case yaml_LN_BREAK:
+		emitter.buffer[emitter.buffer_pos] = '\n'
+		emitter.buffer_pos += 1
+	case yaml_CRLN_BREAK:
+		emitter.buffer[emitter.buffer_pos+0] = '\r'
+		emitter.buffer[emitter.buffer_pos+1] = '\n'
+		emitter.buffer_pos += 2
+	default:
+		panic("unknown line break setting")
+	}
+	emitter.column = 0
+	emitter.line++
+	return true
+}
+
+// Copy a character from a string into buffer.
+func write(emitter *yaml_emitter_t, s []byte, i *int) bool {
+	if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) {
+		return false
+	}
+	p := emitter.buffer_pos
+	w := width(s[*i])
+	switch w {
+	case 4:
+		emitter.buffer[p+3] = s[*i+3]
+		fallthrough
+	case 3:
+		emitter.buffer[p+2] = s[*i+2]
+		fallthrough
+	case 2:
+		emitter.buffer[p+1] = s[*i+1]
+		fallthrough
+	case 1:
+		emitter.buffer[p+0] = s[*i+0]
+	default:
+		panic("unknown character width")
+	}
+	emitter.column++
+	emitter.buffer_pos += w
+	*i += w
+	return true
+}
+
+// Write a whole string into buffer.
+func write_all(emitter *yaml_emitter_t, s []byte) bool {
+	for i := 0; i < len(s); {
+		if !write(emitter, s, &i) {
+			return false
+		}
+	}
+	return true
+}
+
+// Copy a line break character from a string into buffer.
+func write_break(emitter *yaml_emitter_t, s []byte, i *int) bool {
+	if s[*i] == '\n' {
+		if !put_break(emitter) {
+			return false
+		}
+		*i++
+	} else {
+		if !write(emitter, s, i) {
+			return false
+		}
+		emitter.column = 0
+		emitter.line++
+	}
+	return true
+}
+
+// Set an emitter error and return false.
+func yaml_emitter_set_emitter_error(emitter *yaml_emitter_t, problem string) bool {
+	emitter.error = yaml_EMITTER_ERROR
+	emitter.problem = problem
+	return false
+}
+
+// Emit an event.
+func yaml_emitter_emit(emitter *yaml_emitter_t, event *yaml_event_t) bool {
+	emitter.events = append(emitter.events, *event)
+	for !yaml_emitter_need_more_events(emitter) {
+		event := &emitter.events[emitter.events_head]
+		if !yaml_emitter_analyze_event(emitter, event) {
+			return false
+		}
+		if !yaml_emitter_state_machine(emitter, event) {
+			return false
+		}
+		yaml_event_delete(event)
+		emitter.events_head++
+	}
+	return true
+}
+
+// Check if we need to accumulate more events before emitting.
+//
+// We accumulate extra
+//  - 1 event for DOCUMENT-START
+//  - 2 events for SEQUENCE-START
+//  - 3 events for MAPPING-START
+//
+func yaml_emitter_need_more_events(emitter *yaml_emitter_t) bool {
+	if emitter.events_head == len(emitter.events) {
+		return true
+	}
+	var accumulate int
+	switch emitter.events[emitter.events_head].typ {
+	case yaml_DOCUMENT_START_EVENT:
+		accumulate = 1
+		break
+	case yaml_SEQUENCE_START_EVENT:
+		accumulate = 2
+		break
+	case yaml_MAPPING_START_EVENT:
+		accumulate = 3
+		break
+	default:
+		return false
+	}
+	if len(emitter.events)-emitter.events_head > accumulate {
+		return false
+	}
+	var level int
+	for i := emitter.events_head; i < len(emitter.events); i++ {
+		switch emitter.events[i].typ {
+		case yaml_STREAM_START_EVENT, yaml_DOCUMENT_START_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT:
+			level++
+		case yaml_STREAM_END_EVENT, yaml_DOCUMENT_END_EVENT, yaml_SEQUENCE_END_EVENT, yaml_MAPPING_END_EVENT:
+			level--
+		}
+		if level == 0 {
+			return false
+		}
+	}
+	return true
+}
+
+// Append a directive to the directives stack.
+func yaml_emitter_append_tag_directive(emitter *yaml_emitter_t, value *yaml_tag_directive_t, allow_duplicates bool) bool {
+	for i := 0; i < len(emitter.tag_directives); i++ {
+		if bytes.Equal(value.handle, emitter.tag_directives[i].handle) {
+			if allow_duplicates {
+				return true
+			}
+			return yaml_emitter_set_emitter_error(emitter, "duplicate %TAG directive")
+		}
+	}
+
+	// [Go] Do we actually need to copy this given garbage collection
+	// and the lack of deallocating destructors?
+	tag_copy := yaml_tag_directive_t{
+		handle: make([]byte, len(value.handle)),
+		prefix: make([]byte, len(value.prefix)),
+	}
+	copy(tag_copy.handle, value.handle)
+	copy(tag_copy.prefix, value.prefix)
+	emitter.tag_directives = append(emitter.tag_directives, tag_copy)
+	return true
+}
+
+// Increase the indentation level.
+func yaml_emitter_increase_indent(emitter *yaml_emitter_t, flow, indentless bool) bool {
+	emitter.indents = append(emitter.indents, emitter.indent)
+	if emitter.indent < 0 {
+		if flow {
+			emitter.indent = emitter.best_indent
+		} else {
+			emitter.indent = 0
+		}
+	} else if !indentless {
+		emitter.indent += emitter.best_indent
+	}
+	return true
+}
+
+// State dispatcher.
+func yaml_emitter_state_machine(emitter *yaml_emitter_t, event *yaml_event_t) bool {
+	switch emitter.state {
+	default:
+	case yaml_EMIT_STREAM_START_STATE:
+		return yaml_emitter_emit_stream_start(emitter, event)
+
+	case yaml_EMIT_FIRST_DOCUMENT_START_STATE:
+		return yaml_emitter_emit_document_start(emitter, event, true)
+
+	case yaml_EMIT_DOCUMENT_START_STATE:
+		return yaml_emitter_emit_document_start(emitter, event, false)
+
+	case yaml_EMIT_DOCUMENT_CONTENT_STATE:
+		return yaml_emitter_emit_document_content(emitter, event)
+
+	case yaml_EMIT_DOCUMENT_END_STATE:
+		return yaml_emitter_emit_document_end(emitter, event)
+
+	case yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE:
+		return yaml_emitter_emit_flow_sequence_item(emitter, event, true)
+
+	case yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE:
+		return yaml_emitter_emit_flow_sequence_item(emitter, event, false)
+
+	case yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE:
+		return yaml_emitter_emit_flow_mapping_key(emitter, event, true)
+
+	case yaml_EMIT_FLOW_MAPPING_KEY_STATE:
+		return yaml_emitter_emit_flow_mapping_key(emitter, event, false)
+
+	case yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE:
+		return yaml_emitter_emit_flow_mapping_value(emitter, event, true)
+
+	case yaml_EMIT_FLOW_MAPPING_VALUE_STATE:
+		return yaml_emitter_emit_flow_mapping_value(emitter, event, false)
+
+	case yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE:
+		return yaml_emitter_emit_block_sequence_item(emitter, event, true)
+
+	case yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE:
+		return yaml_emitter_emit_block_sequence_item(emitter, event, false)
+
+	case yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE:
+		return yaml_emitter_emit_block_mapping_key(emitter, event, true)
+
+	case yaml_EMIT_BLOCK_MAPPING_KEY_STATE:
+		return yaml_emitter_emit_block_mapping_key(emitter, event, false)
+
+	case yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE:
+		return yaml_emitter_emit_block_mapping_value(emitter, event, true)
+
+	case yaml_EMIT_BLOCK_MAPPING_VALUE_STATE:
+		return yaml_emitter_emit_block_mapping_value(emitter, event, false)
+
+	case yaml_EMIT_END_STATE:
+		return yaml_emitter_set_emitter_error(emitter, "expected nothing after STREAM-END")
+	}
+	panic("invalid emitter state")
+}
+
+// Expect STREAM-START.
+func yaml_emitter_emit_stream_start(emitter *yaml_emitter_t, event *yaml_event_t) bool {
+	if event.typ != yaml_STREAM_START_EVENT {
+		return yaml_emitter_set_emitter_error(emitter, "expected STREAM-START")
+	}
+	if emitter.encoding == yaml_ANY_ENCODING {
+		emitter.encoding = event.encoding
+		if emitter.encoding == yaml_ANY_ENCODING {
+			emitter.encoding = yaml_UTF8_ENCODING
+		}
+	}
+	if emitter.best_indent < 2 || emitter.best_indent > 9 {
+		emitter.best_indent = 2
+	}
+	if emitter.best_width >= 0 && emitter.best_width <= emitter.best_indent*2 {
+		emitter.best_width = 80
+	}
+	if emitter.best_width < 0 {
+		emitter.best_width = 1<<31 - 1
+	}
+	if emitter.line_break == yaml_ANY_BREAK {
+		emitter.line_break = yaml_LN_BREAK
+	}
+
+	emitter.indent = -1
+	emitter.line = 0
+	emitter.column = 0
+	emitter.whitespace = true
+	emitter.indention = true
+
+	if emitter.encoding != yaml_UTF8_ENCODING {
+		if !yaml_emitter_write_bom(emitter) {
+			return false
+		}
+	}
+	emitter.state = yaml_EMIT_FIRST_DOCUMENT_START_STATE
+	return true
+}
+
+// Expect DOCUMENT-START or STREAM-END.
+func yaml_emitter_emit_document_start(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool {
+
+	if event.typ == yaml_DOCUMENT_START_EVENT {
+
+		if event.version_directive != nil {
+			if !yaml_emitter_analyze_version_directive(emitter, event.version_directive) {
+				return false
+			}
+		}
+
+		for i := 0; i < len(event.tag_directives); i++ {
+			tag_directive := &event.tag_directives[i]
+			if !yaml_emitter_analyze_tag_directive(emitter, tag_directive) {
+				return false
+			}
+			if !yaml_emitter_append_tag_directive(emitter, tag_directive, false) {
+				return false
+			}
+		}
+
+		for i := 0; i < len(default_tag_directives); i++ {
+			tag_directive := &default_tag_directives[i]
+			if !yaml_emitter_append_tag_directive(emitter, tag_directive, true) {
+				return false
+			}
+		}
+
+		implicit := event.implicit
+		if !first || emitter.canonical {
+			implicit = false
+		}
+
+		if emitter.open_ended && (event.version_directive != nil || len(event.tag_directives) > 0) {
+			if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) {
+				return false
+			}
+			if !yaml_emitter_write_indent(emitter) {
+				return false
+			}
+		}
+
+		if event.version_directive != nil {
+			implicit = false
+			if !yaml_emitter_write_indicator(emitter, []byte("%YAML"), true, false, false) {
+				return false
+			}
+			if !yaml_emitter_write_indicator(emitter, []byte("1.1"), true, false, false) {
+				return false
+			}
+			if !yaml_emitter_write_indent(emitter) {
+				return false
+			}
+		}
+
+		if len(event.tag_directives) > 0 {
+			implicit = false
+			for i := 0; i < len(event.tag_directives); i++ {
+				tag_directive := &event.tag_directives[i]
+				if !yaml_emitter_write_indicator(emitter, []byte("%TAG"), true, false, false) {
+					return false
+				}
+				if !yaml_emitter_write_tag_handle(emitter, tag_directive.handle) {
+					return false
+				}
+				if !yaml_emitter_write_tag_content(emitter, tag_directive.prefix, true) {
+					return false
+				}
+				if !yaml_emitter_write_indent(emitter) {
+					return false
+				}
+			}
+		}
+
+		if yaml_emitter_check_empty_document(emitter) {
+			implicit = false
+		}
+		if !implicit {
+			if !yaml_emitter_write_indent(emitter) {
+				return false
+			}
+			if !yaml_emitter_write_indicator(emitter, []byte("---"), true, false, false) {
+				return false
+			}
+			if emitter.canonical {
+				if !yaml_emitter_write_indent(emitter) {
+					return false
+				}
+			}
+		}
+
+		emitter.state = yaml_EMIT_DOCUMENT_CONTENT_STATE
+		return true
+	}
+
+	if event.typ == yaml_STREAM_END_EVENT {
+		if emitter.open_ended {
+			if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) {
+				return false
+			}
+			if !yaml_emitter_write_indent(emitter) {
+				return false
+			}
+		}
+		if !yaml_emitter_flush(emitter) {
+			return false
+		}
+		emitter.state = yaml_EMIT_END_STATE
+		return true
+	}
+
+	return yaml_emitter_set_emitter_error(emitter, "expected DOCUMENT-START or STREAM-END")
+}
+
+// Expect the root node.
+func yaml_emitter_emit_document_content(emitter *yaml_emitter_t, event *yaml_event_t) bool {
+	emitter.states = append(emitter.states, yaml_EMIT_DOCUMENT_END_STATE)
+	return yaml_emitter_emit_node(emitter, event, true, false, false, false)
+}
+
+// Expect DOCUMENT-END.
+func yaml_emitter_emit_document_end(emitter *yaml_emitter_t, event *yaml_event_t) bool {
+	if event.typ != yaml_DOCUMENT_END_EVENT {
+		return yaml_emitter_set_emitter_error(emitter, "expected DOCUMENT-END")
+	}
+	if !yaml_emitter_write_indent(emitter) {
+		return false
+	}
+	if !event.implicit {
+		// [Go] Allocate the slice elsewhere.
+		if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) {
+			return false
+		}
+		if !yaml_emitter_write_indent(emitter) {
+			return false
+		}
+	}
+	if !yaml_emitter_flush(emitter) {
+		return false
+	}
+	emitter.state = yaml_EMIT_DOCUMENT_START_STATE
+	emitter.tag_directives = emitter.tag_directives[:0]
+	return true
+}
+
+// Expect a flow item node.
+func yaml_emitter_emit_flow_sequence_item(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool {
+	if first {
+		if !yaml_emitter_write_indicator(emitter, []byte{'['}, true, true, false) {
+			return false
+		}
+		if !yaml_emitter_increase_indent(emitter, true, false) {
+			return false
+		}
+		emitter.flow_level++
+	}
+
+	if event.typ == yaml_SEQUENCE_END_EVENT {
+		emitter.flow_level--
+		emitter.indent = emitter.indents[len(emitter.indents)-1]
+		emitter.indents = emitter.indents[:len(emitter.indents)-1]
+		if emitter.canonical && !first {
+			if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) {
+				return false
+			}
+			if !yaml_emitter_write_indent(emitter) {
+				return false
+			}
+		}
+		if !yaml_emitter_write_indicator(emitter, []byte{']'}, false, false, false) {
+			return false
+		}
+		emitter.state = emitter.states[len(emitter.states)-1]
+		emitter.states = emitter.states[:len(emitter.states)-1]
+
+		return true
+	}
+
+	if !first {
+		if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) {
+			return false
+		}
+	}
+
+	if emitter.canonical || emitter.column > emitter.best_width {
+		if !yaml_emitter_write_indent(emitter) {
+			return false
+		}
+	}
+	emitter.states = append(emitter.states, yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE)
+	return yaml_emitter_emit_node(emitter, event, false, true, false, false)
+}
+
+// Expect a flow key node.
+func yaml_emitter_emit_flow_mapping_key(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool {
+	if first {
+		if !yaml_emitter_write_indicator(emitter, []byte{'{'}, true, true, false) {
+			return false
+		}
+		if !yaml_emitter_increase_indent(emitter, true, false) {
+			return false
+		}
+		emitter.flow_level++
+	}
+
+	if event.typ == yaml_MAPPING_END_EVENT {
+		emitter.flow_level--
+		emitter.indent = emitter.indents[len(emitter.indents)-1]
+		emitter.indents = emitter.indents[:len(emitter.indents)-1]
+		if emitter.canonical && !first {
+			if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) {
+				return false
+			}
+			if !yaml_emitter_write_indent(emitter) {
+				return false
+			}
+		}
+		if !yaml_emitter_write_indicator(emitter, []byte{'}'}, false, false, false) {
+			return false
+		}
+		emitter.state = emitter.states[len(emitter.states)-1]
+		emitter.states = emitter.states[:len(emitter.states)-1]
+		return true
+	}
+
+	if !first {
+		if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) {
+			return false
+		}
+	}
+	if emitter.canonical || emitter.column > emitter.best_width {
+		if !yaml_emitter_write_indent(emitter) {
+			return false
+		}
+	}
+
+	if !emitter.canonical && yaml_emitter_check_simple_key(emitter) {
+		emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE)
+		return yaml_emitter_emit_node(emitter, event, false, false, true, true)
+	}
+	if !yaml_emitter_write_indicator(emitter, []byte{'?'}, true, false, false) {
+		return false
+	}
+	emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_VALUE_STATE)
+	return yaml_emitter_emit_node(emitter, event, false, false, true, false)
+}
+
+// Expect a flow value node.
+func yaml_emitter_emit_flow_mapping_value(emitter *yaml_emitter_t, event *yaml_event_t, simple bool) bool {
+	if simple {
+		if !yaml_emitter_write_indicator(emitter, []byte{':'}, false, false, false) {
+			return false
+		}
+	} else {
+		if emitter.canonical || emitter.column > emitter.best_width {
+			if !yaml_emitter_write_indent(emitter) {
+				return false
+			}
+		}
+		if !yaml_emitter_write_indicator(emitter, []byte{':'}, true, false, false) {
+			return false
+		}
+	}
+	emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_KEY_STATE)
+	return yaml_emitter_emit_node(emitter, event, false, false, true, false)
+}
+
+// Expect a block item node.
+func yaml_emitter_emit_block_sequence_item(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool {
+	if first {
+		if !yaml_emitter_increase_indent(emitter, false, emitter.mapping_context && !emitter.indention) {
+			return false
+		}
+	}
+	if event.typ == yaml_SEQUENCE_END_EVENT {
+		emitter.indent = emitter.indents[len(emitter.indents)-1]
+		emitter.indents = emitter.indents[:len(emitter.indents)-1]
+		emitter.state = emitter.states[len(emitter.states)-1]
+		emitter.states = emitter.states[:len(emitter.states)-1]
+		return true
+	}
+	if !yaml_emitter_write_indent(emitter) {
+		return false
+	}
+	if !yaml_emitter_write_indicator(emitter, []byte{'-'}, true, false, true) {
+		return false
+	}
+	emitter.states = append(emitter.states, yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE)
+	return yaml_emitter_emit_node(emitter, event, false, true, false, false)
+}
+
+// Expect a block key node.
+func yaml_emitter_emit_block_mapping_key(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool {
+	if first {
+		if !yaml_emitter_increase_indent(emitter, false, false) {
+			return false
+		}
+	}
+	if event.typ == yaml_MAPPING_END_EVENT {
+		emitter.indent = emitter.indents[len(emitter.indents)-1]
+		emitter.indents = emitter.indents[:len(emitter.indents)-1]
+		emitter.state = emitter.states[len(emitter.states)-1]
+		emitter.states = emitter.states[:len(emitter.states)-1]
+		return true
+	}
+	if !yaml_emitter_write_indent(emitter) {
+		return false
+	}
+	if yaml_emitter_check_simple_key(emitter) {
+		emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE)
+		return yaml_emitter_emit_node(emitter, event, false, false, true, true)
+	}
+	if !yaml_emitter_write_indicator(emitter, []byte{'?'}, true, false, true) {
+		return false
+	}
+	emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_VALUE_STATE)
+	return yaml_emitter_emit_node(emitter, event, false, false, true, false)
+}
+
+// Expect a block value node.
+func yaml_emitter_emit_block_mapping_value(emitter *yaml_emitter_t, event *yaml_event_t, simple bool) bool {
+	if simple {
+		if !yaml_emitter_write_indicator(emitter, []byte{':'}, false, false, false) {
+			return false
+		}
+	} else {
+		if !yaml_emitter_write_indent(emitter) {
+			return false
+		}
+		if !yaml_emitter_write_indicator(emitter, []byte{':'}, true, false, true) {
+			return false
+		}
+	}
+	emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_KEY_STATE)
+	return yaml_emitter_emit_node(emitter, event, false, false, true, false)
+}
+
+// Expect a node.
+func yaml_emitter_emit_node(emitter *yaml_emitter_t, event *yaml_event_t,
+	root bool, sequence bool, mapping bool, simple_key bool) bool {
+
+	emitter.root_context = root
+	emitter.sequence_context = sequence
+	emitter.mapping_context = mapping
+	emitter.simple_key_context = simple_key
+
+	switch event.typ {
+	case yaml_ALIAS_EVENT:
+		return yaml_emitter_emit_alias(emitter, event)
+	case yaml_SCALAR_EVENT:
+		return yaml_emitter_emit_scalar(emitter, event)
+	case yaml_SEQUENCE_START_EVENT:
+		return yaml_emitter_emit_sequence_start(emitter, event)
+	case yaml_MAPPING_START_EVENT:
+		return yaml_emitter_emit_mapping_start(emitter, event)
+	default:
+		return yaml_emitter_set_emitter_error(emitter,
+			fmt.Sprintf("expected SCALAR, SEQUENCE-START, MAPPING-START, or ALIAS, but got %v", event.typ))
+	}
+}
+
+// Expect ALIAS.
+func yaml_emitter_emit_alias(emitter *yaml_emitter_t, event *yaml_event_t) bool {
+	if !yaml_emitter_process_anchor(emitter) {
+		return false
+	}
+	emitter.state = emitter.states[len(emitter.states)-1]
+	emitter.states = emitter.states[:len(emitter.states)-1]
+	return true
+}
+
+// Expect SCALAR.
+func yaml_emitter_emit_scalar(emitter *yaml_emitter_t, event *yaml_event_t) bool {
+	if !yaml_emitter_select_scalar_style(emitter, event) {
+		return false
+	}
+	if !yaml_emitter_process_anchor(emitter) {
+		return false
+	}
+	if !yaml_emitter_process_tag(emitter) {
+		return false
+	}
+	if !yaml_emitter_increase_indent(emitter, true, false) {
+		return false
+	}
+	if !yaml_emitter_process_scalar(emitter) {
+		return false
+	}
+	emitter.indent = emitter.indents[len(emitter.indents)-1]
+	emitter.indents = emitter.indents[:len(emitter.indents)-1]
+	emitter.state = emitter.states[len(emitter.states)-1]
+	emitter.states = emitter.states[:len(emitter.states)-1]
+	return true
+}
+
+// Expect SEQUENCE-START.
+func yaml_emitter_emit_sequence_start(emitter *yaml_emitter_t, event *yaml_event_t) bool {
+	if !yaml_emitter_process_anchor(emitter) {
+		return false
+	}
+	if !yaml_emitter_process_tag(emitter) {
+		return false
+	}
+	if emitter.flow_level > 0 || emitter.canonical || event.sequence_style() == yaml_FLOW_SEQUENCE_STYLE ||
+		yaml_emitter_check_empty_sequence(emitter) {
+		emitter.state = yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE
+	} else {
+		emitter.state = yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE
+	}
+	return true
+}
+
+// Expect MAPPING-START.
+func yaml_emitter_emit_mapping_start(emitter *yaml_emitter_t, event *yaml_event_t) bool {
+	if !yaml_emitter_process_anchor(emitter) {
+		return false
+	}
+	if !yaml_emitter_process_tag(emitter) {
+		return false
+	}
+	if emitter.flow_level > 0 || emitter.canonical || event.mapping_style() == yaml_FLOW_MAPPING_STYLE ||
+		yaml_emitter_check_empty_mapping(emitter) {
+		emitter.state = yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE
+	} else {
+		emitter.state = yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE
+	}
+	return true
+}
+
+// Check if the document content is an empty scalar.
+func yaml_emitter_check_empty_document(emitter *yaml_emitter_t) bool {
+	return false // [Go] Huh?
+}
+
+// Check if the next events represent an empty sequence.
+func yaml_emitter_check_empty_sequence(emitter *yaml_emitter_t) bool {
+	if len(emitter.events)-emitter.events_head < 2 {
+		return false
+	}
+	return emitter.events[emitter.events_head].typ == yaml_SEQUENCE_START_EVENT &&
+		emitter.events[emitter.events_head+1].typ == yaml_SEQUENCE_END_EVENT
+}
+
+// Check if the next events represent an empty mapping.
+func yaml_emitter_check_empty_mapping(emitter *yaml_emitter_t) bool {
+	if len(emitter.events)-emitter.events_head < 2 {
+		return false
+	}
+	return emitter.events[emitter.events_head].typ == yaml_MAPPING_START_EVENT &&
+		emitter.events[emitter.events_head+1].typ == yaml_MAPPING_END_EVENT
+}
+
+// Check if the next node can be expressed as a simple key.
+func yaml_emitter_check_simple_key(emitter *yaml_emitter_t) bool {
+	length := 0
+	switch emitter.events[emitter.events_head].typ {
+	case yaml_ALIAS_EVENT:
+		length += len(emitter.anchor_data.anchor)
+	case yaml_SCALAR_EVENT:
+		if emitter.scalar_data.multiline {
+			return false
+		}
+		length += len(emitter.anchor_data.anchor) +
+			len(emitter.tag_data.handle) +
+			len(emitter.tag_data.suffix) +
+			len(emitter.scalar_data.value)
+	case yaml_SEQUENCE_START_EVENT:
+		if !yaml_emitter_check_empty_sequence(emitter) {
+			return false
+		}
+		length += len(emitter.anchor_data.anchor) +
+			len(emitter.tag_data.handle) +
+			len(emitter.tag_data.suffix)
+	case yaml_MAPPING_START_EVENT:
+		if !yaml_emitter_check_empty_mapping(emitter) {
+			return false
+		}
+		length += len(emitter.anchor_data.anchor) +
+			len(emitter.tag_data.handle) +
+			len(emitter.tag_data.suffix)
+	default:
+		return false
+	}
+	return length <= 128
+}
+
+// Determine an acceptable scalar style.
+func yaml_emitter_select_scalar_style(emitter *yaml_emitter_t, event *yaml_event_t) bool {
+
+	no_tag := len(emitter.tag_data.handle) == 0 && len(emitter.tag_data.suffix) == 0
+	if no_tag && !event.implicit && !event.quoted_implicit {
+		return yaml_emitter_set_emitter_error(emitter, "neither tag nor implicit flags are specified")
+	}
+
+	style := event.scalar_style()
+	if style == yaml_ANY_SCALAR_STYLE {
+		style = yaml_PLAIN_SCALAR_STYLE
+	}
+	if emitter.canonical {
+		style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
+	}
+	if emitter.simple_key_context && emitter.scalar_data.multiline {
+		style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
+	}
+
+	if style == yaml_PLAIN_SCALAR_STYLE {
+		if emitter.flow_level > 0 && !emitter.scalar_data.flow_plain_allowed ||
+			emitter.flow_level == 0 && !emitter.scalar_data.block_plain_allowed {
+			style = yaml_SINGLE_QUOTED_SCALAR_STYLE
+		}
+		if len(emitter.scalar_data.value) == 0 && (emitter.flow_level > 0 || emitter.simple_key_context) {
+			style = yaml_SINGLE_QUOTED_SCALAR_STYLE
+		}
+		if no_tag && !event.implicit {
+			style = yaml_SINGLE_QUOTED_SCALAR_STYLE
+		}
+	}
+	if style == yaml_SINGLE_QUOTED_SCALAR_STYLE {
+		if !emitter.scalar_data.single_quoted_allowed {
+			style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
+		}
+	}
+	if style == yaml_LITERAL_SCALAR_STYLE || style == yaml_FOLDED_SCALAR_STYLE {
+		if !emitter.scalar_data.block_allowed || emitter.flow_level > 0 || emitter.simple_key_context {
+			style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
+		}
+	}
+
+	if no_tag && !event.quoted_implicit && style != yaml_PLAIN_SCALAR_STYLE {
+		emitter.tag_data.handle = []byte{'!'}
+	}
+	emitter.scalar_data.style = style
+	return true
+}
+
+// Write an anchor.
+func yaml_emitter_process_anchor(emitter *yaml_emitter_t) bool {
+	if emitter.anchor_data.anchor == nil {
+		return true
+	}
+	c := []byte{'&'}
+	if emitter.anchor_data.alias {
+		c[0] = '*'
+	}
+	if !yaml_emitter_write_indicator(emitter, c, true, false, false) {
+		return false
+	}
+	return yaml_emitter_write_anchor(emitter, emitter.anchor_data.anchor)
+}
+
+// Write a tag.
+func yaml_emitter_process_tag(emitter *yaml_emitter_t) bool {
+	if len(emitter.tag_data.handle) == 0 && len(emitter.tag_data.suffix) == 0 {
+		return true
+	}
+	if len(emitter.tag_data.handle) > 0 {
+		if !yaml_emitter_write_tag_handle(emitter, emitter.tag_data.handle) {
+			return false
+		}
+		if len(emitter.tag_data.suffix) > 0 {
+			if !yaml_emitter_write_tag_content(emitter, emitter.tag_data.suffix, false) {
+				return false
+			}
+		}
+	} else {
+		// [Go] Allocate these slices elsewhere.
+		if !yaml_emitter_write_indicator(emitter, []byte("!<"), true, false, false) {
+			return false
+		}
+		if !yaml_emitter_write_tag_content(emitter, emitter.tag_data.suffix, false) {
+			return false
+		}
+		if !yaml_emitter_write_indicator(emitter, []byte{'>'}, false, false, false) {
+			return false
+		}
+	}
+	return true
+}
+
+// Write a scalar.
+func yaml_emitter_process_scalar(emitter *yaml_emitter_t) bool {
+	switch emitter.scalar_data.style {
+	case yaml_PLAIN_SCALAR_STYLE:
+		return yaml_emitter_write_plain_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context)
+
+	case yaml_SINGLE_QUOTED_SCALAR_STYLE:
+		return yaml_emitter_write_single_quoted_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context)
+
+	case yaml_DOUBLE_QUOTED_SCALAR_STYLE:
+		return yaml_emitter_write_double_quoted_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context)
+
+	case yaml_LITERAL_SCALAR_STYLE:
+		return yaml_emitter_write_literal_scalar(emitter, emitter.scalar_data.value)
+
+	case yaml_FOLDED_SCALAR_STYLE:
+		return yaml_emitter_write_folded_scalar(emitter, emitter.scalar_data.value)
+	}
+	panic("unknown scalar style")
+}
+
+// Check if a %YAML directive is valid.
+func yaml_emitter_analyze_version_directive(emitter *yaml_emitter_t, version_directive *yaml_version_directive_t) bool {
+	if version_directive.major != 1 || version_directive.minor != 1 {
+		return yaml_emitter_set_emitter_error(emitter, "incompatible %YAML directive")
+	}
+	return true
+}
+
+// Check if a %TAG directive is valid.
+func yaml_emitter_analyze_tag_directive(emitter *yaml_emitter_t, tag_directive *yaml_tag_directive_t) bool {
+	handle := tag_directive.handle
+	prefix := tag_directive.prefix
+	if len(handle) == 0 {
+		return yaml_emitter_set_emitter_error(emitter, "tag handle must not be empty")
+	}
+	if handle[0] != '!' {
+		return yaml_emitter_set_emitter_error(emitter, "tag handle must start with '!'")
+	}
+	if handle[len(handle)-1] != '!' {
+		return yaml_emitter_set_emitter_error(emitter, "tag handle must end with '!'")
+	}
+	for i := 1; i < len(handle)-1; i += width(handle[i]) {
+		if !is_alpha(handle, i) {
+			return yaml_emitter_set_emitter_error(emitter, "tag handle must contain alphanumerical characters only")
+		}
+	}
+	if len(prefix) == 0 {
+		return yaml_emitter_set_emitter_error(emitter, "tag prefix must not be empty")
+	}
+	return true
+}
+
+// Check if an anchor is valid.
+func yaml_emitter_analyze_anchor(emitter *yaml_emitter_t, anchor []byte, alias bool) bool {
+	if len(anchor) == 0 {
+		problem := "anchor value must not be empty"
+		if alias {
+			problem = "alias value must not be empty"
+		}
+		return yaml_emitter_set_emitter_error(emitter, problem)
+	}
+	for i := 0; i < len(anchor); i += width(anchor[i]) {
+		if !is_alpha(anchor, i) {
+			problem := "anchor value must contain alphanumerical characters only"
+			if alias {
+				problem = "alias value must contain alphanumerical characters only"
+			}
+			return yaml_emitter_set_emitter_error(emitter, problem)
+		}
+	}
+	emitter.anchor_data.anchor = anchor
+	emitter.anchor_data.alias = alias
+	return true
+}
+
+// Check if a tag is valid.
+func yaml_emitter_analyze_tag(emitter *yaml_emitter_t, tag []byte) bool {
+	if len(tag) == 0 {
+		return yaml_emitter_set_emitter_error(emitter, "tag value must not be empty")
+	}
+	for i := 0; i < len(emitter.tag_directives); i++ {
+		tag_directive := &emitter.tag_directives[i]
+		if bytes.HasPrefix(tag, tag_directive.prefix) {
+			emitter.tag_data.handle = tag_directive.handle
+			emitter.tag_data.suffix = tag[len(tag_directive.prefix):]
+			return true
+		}
+	}
+	emitter.tag_data.suffix = tag
+	return true
+}
+
+// Check if a scalar is valid.
+func yaml_emitter_analyze_scalar(emitter *yaml_emitter_t, value []byte) bool {
+	var (
+		block_indicators   = false
+		flow_indicators    = false
+		line_breaks        = false
+		special_characters = false
+
+		leading_space  = false
+		leading_break  = false
+		trailing_space = false
+		trailing_break = false
+		break_space    = false
+		space_break    = false
+
+		preceded_by_whitespace = false
+		followed_by_whitespace = false
+		previous_space         = false
+		previous_break         = false
+	)
+
+	emitter.scalar_data.value = value
+
+	if len(value) == 0 {
+		emitter.scalar_data.multiline = false
+		emitter.scalar_data.flow_plain_allowed = false
+		emitter.scalar_data.block_plain_allowed = true
+		emitter.scalar_data.single_quoted_allowed = true
+		emitter.scalar_data.block_allowed = false
+		return true
+	}
+
+	if len(value) >= 3 && ((value[0] == '-' && value[1] == '-' && value[2] == '-') || (value[0] == '.' && value[1] == '.' && value[2] == '.')) {
+		block_indicators = true
+		flow_indicators = true
+	}
+
+	preceded_by_whitespace = true
+	for i, w := 0, 0; i < len(value); i += w {
+		w = width(value[i])
+		followed_by_whitespace = i+w >= len(value) || is_blank(value, i+w)
+
+		if i == 0 {
+			switch value[i] {
+			case '#', ',', '[', ']', '{', '}', '&', '*', '!', '|', '>', '\'', '"', '%', '@', '`':
+				flow_indicators = true
+				block_indicators = true
+			case '?', ':':
+				flow_indicators = true
+				if followed_by_whitespace {
+					block_indicators = true
+				}
+			case '-':
+				if followed_by_whitespace {
+					flow_indicators = true
+					block_indicators = true
+				}
+			}
+		} else {
+			switch value[i] {
+			case ',', '?', '[', ']', '{', '}':
+				flow_indicators = true
+			case ':':
+				flow_indicators = true
+				if followed_by_whitespace {
+					block_indicators = true
+				}
+			case '#':
+				if preceded_by_whitespace {
+					flow_indicators = true
+					block_indicators = true
+				}
+			}
+		}
+
+		if !is_printable(value, i) || !is_ascii(value, i) && !emitter.unicode {
+			special_characters = true
+		}
+		if is_space(value, i) {
+			if i == 0 {
+				leading_space = true
+			}
+			if i+width(value[i]) == len(value) {
+				trailing_space = true
+			}
+			if previous_break {
+				break_space = true
+			}
+			previous_space = true
+			previous_break = false
+		} else if is_break(value, i) {
+			line_breaks = true
+			if i == 0 {
+				leading_break = true
+			}
+			if i+width(value[i]) == len(value) {
+				trailing_break = true
+			}
+			if previous_space {
+				space_break = true
+			}
+			previous_space = false
+			previous_break = true
+		} else {
+			previous_space = false
+			previous_break = false
+		}
+
+		// [Go]: Why 'z'? Couldn't be the end of the string as that's the loop condition.
+		preceded_by_whitespace = is_blankz(value, i)
+	}
+
+	emitter.scalar_data.multiline = line_breaks
+	emitter.scalar_data.flow_plain_allowed = true
+	emitter.scalar_data.block_plain_allowed = true
+	emitter.scalar_data.single_quoted_allowed = true
+	emitter.scalar_data.block_allowed = true
+
+	if leading_space || leading_break || trailing_space || trailing_break {
+		emitter.scalar_data.flow_plain_allowed = false
+		emitter.scalar_data.block_plain_allowed = false
+	}
+	if trailing_space {
+		emitter.scalar_data.block_allowed = false
+	}
+	if break_space {
+		emitter.scalar_data.flow_plain_allowed = false
+		emitter.scalar_data.block_plain_allowed = false
+		emitter.scalar_data.single_quoted_allowed = false
+	}
+	if space_break || special_characters {
+		emitter.scalar_data.flow_plain_allowed = false
+		emitter.scalar_data.block_plain_allowed = false
+		emitter.scalar_data.single_quoted_allowed = false
+		emitter.scalar_data.block_allowed = false
+	}
+	if line_breaks {
+		emitter.scalar_data.flow_plain_allowed = false
+		emitter.scalar_data.block_plain_allowed = false
+	}
+	if flow_indicators {
+		emitter.scalar_data.flow_plain_allowed = false
+	}
+	if block_indicators {
+		emitter.scalar_data.block_plain_allowed = false
+	}
+	return true
+}
+
+// Check if the event data is valid.
+func yaml_emitter_analyze_event(emitter *yaml_emitter_t, event *yaml_event_t) bool {
+
+	emitter.anchor_data.anchor = nil
+	emitter.tag_data.handle = nil
+	emitter.tag_data.suffix = nil
+	emitter.scalar_data.value = nil
+
+	switch event.typ {
+	case yaml_ALIAS_EVENT:
+		if !yaml_emitter_analyze_anchor(emitter, event.anchor, true) {
+			return false
+		}
+
+	case yaml_SCALAR_EVENT:
+		if len(event.anchor) > 0 {
+			if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) {
+				return false
+			}
+		}
+		if len(event.tag) > 0 && (emitter.canonical || (!event.implicit && !event.quoted_implicit)) {
+			if !yaml_emitter_analyze_tag(emitter, event.tag) {
+				return false
+			}
+		}
+		if !yaml_emitter_analyze_scalar(emitter, event.value) {
+			return false
+		}
+
+	case yaml_SEQUENCE_START_EVENT:
+		if len(event.anchor) > 0 {
+			if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) {
+				return false
+			}
+		}
+		if len(event.tag) > 0 && (emitter.canonical || !event.implicit) {
+			if !yaml_emitter_analyze_tag(emitter, event.tag) {
+				return false
+			}
+		}
+
+	case yaml_MAPPING_START_EVENT:
+		if len(event.anchor) > 0 {
+			if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) {
+				return false
+			}
+		}
+		if len(event.tag) > 0 && (emitter.canonical || !event.implicit) {
+			if !yaml_emitter_analyze_tag(emitter, event.tag) {
+				return false
+			}
+		}
+	}
+	return true
+}
+
+// Write the BOM character.
+func yaml_emitter_write_bom(emitter *yaml_emitter_t) bool {
+	if !flush(emitter) {
+		return false
+	}
+	pos := emitter.buffer_pos
+	emitter.buffer[pos+0] = '\xEF'
+	emitter.buffer[pos+1] = '\xBB'
+	emitter.buffer[pos+2] = '\xBF'
+	emitter.buffer_pos += 3
+	return true
+}
+
+func yaml_emitter_write_indent(emitter *yaml_emitter_t) bool {
+	indent := emitter.indent
+	if indent < 0 {
+		indent = 0
+	}
+	if !emitter.indention || emitter.column > indent || (emitter.column == indent && !emitter.whitespace) {
+		if !put_break(emitter) {
+			return false
+		}
+	}
+	for emitter.column < indent {
+		if !put(emitter, ' ') {
+			return false
+		}
+	}
+	emitter.whitespace = true
+	emitter.indention = true
+	return true
+}
+
+func yaml_emitter_write_indicator(emitter *yaml_emitter_t, indicator []byte, need_whitespace, is_whitespace, is_indention bool) bool {
+	if need_whitespace && !emitter.whitespace {
+		if !put(emitter, ' ') {
+			return false
+		}
+	}
+	if !write_all(emitter, indicator) {
+		return false
+	}
+	emitter.whitespace = is_whitespace
+	emitter.indention = (emitter.indention && is_indention)
+	emitter.open_ended = false
+	return true
+}
+
+func yaml_emitter_write_anchor(emitter *yaml_emitter_t, value []byte) bool {
+	if !write_all(emitter, value) {
+		return false
+	}
+	emitter.whitespace = false
+	emitter.indention = false
+	return true
+}
+
+func yaml_emitter_write_tag_handle(emitter *yaml_emitter_t, value []byte) bool {
+	if !emitter.whitespace {
+		if !put(emitter, ' ') {
+			return false
+		}
+	}
+	if !write_all(emitter, value) {
+		return false
+	}
+	emitter.whitespace = false
+	emitter.indention = false
+	return true
+}
+
+func yaml_emitter_write_tag_content(emitter *yaml_emitter_t, value []byte, need_whitespace bool) bool {
+	if need_whitespace && !emitter.whitespace {
+		if !put(emitter, ' ') {
+			return false
+		}
+	}
+	for i := 0; i < len(value); {
+		var must_write bool
+		switch value[i] {
+		case ';', '/', '?', ':', '@', '&', '=', '+', '$', ',', '_', '.', '~', '*', '\'', '(', ')', '[', ']':
+			must_write = true
+		default:
+			must_write = is_alpha(value, i)
+		}
+		if must_write {
+			if !write(emitter, value, &i) {
+				return false
+			}
+		} else {
+			w := width(value[i])
+			for k := 0; k < w; k++ {
+				octet := value[i]
+				i++
+				if !put(emitter, '%') {
+					return false
+				}
+
+				c := octet >> 4
+				if c < 10 {
+					c += '0'
+				} else {
+					c += 'A' - 10
+				}
+				if !put(emitter, c) {
+					return false
+				}
+
+				c = octet & 0x0f
+				if c < 10 {
+					c += '0'
+				} else {
+					c += 'A' - 10
+				}
+				if !put(emitter, c) {
+					return false
+				}
+			}
+		}
+	}
+	emitter.whitespace = false
+	emitter.indention = false
+	return true
+}
+
+func yaml_emitter_write_plain_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool {
+	if !emitter.whitespace {
+		if !put(emitter, ' ') {
+			return false
+		}
+	}
+
+	spaces := false
+	breaks := false
+	for i := 0; i < len(value); {
+		if is_space(value, i) {
+			if allow_breaks && !spaces && emitter.column > emitter.best_width && !is_space(value, i+1) {
+				if !yaml_emitter_write_indent(emitter) {
+					return false
+				}
+				i += width(value[i])
+			} else {
+				if !write(emitter, value, &i) {
+					return false
+				}
+			}
+			spaces = true
+		} else if is_break(value, i) {
+			if !breaks && value[i] == '\n' {
+				if !put_break(emitter) {
+					return false
+				}
+			}
+			if !write_break(emitter, value, &i) {
+				return false
+			}
+			emitter.indention = true
+			breaks = true
+		} else {
+			if breaks {
+				if !yaml_emitter_write_indent(emitter) {
+					return false
+				}
+			}
+			if !write(emitter, value, &i) {
+				return false
+			}
+			emitter.indention = false
+			spaces = false
+			breaks = false
+		}
+	}
+
+	emitter.whitespace = false
+	emitter.indention = false
+	if emitter.root_context {
+		emitter.open_ended = true
+	}
+
+	return true
+}
+
+func yaml_emitter_write_single_quoted_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool {
+
+	if !yaml_emitter_write_indicator(emitter, []byte{'\''}, true, false, false) {
+		return false
+	}
+
+	spaces := false
+	breaks := false
+	for i := 0; i < len(value); {
+		if is_space(value, i) {
+			if allow_breaks && !spaces && emitter.column > emitter.best_width && i > 0 && i < len(value)-1 && !is_space(value, i+1) {
+				if !yaml_emitter_write_indent(emitter) {
+					return false
+				}
+				i += width(value[i])
+			} else {
+				if !write(emitter, value, &i) {
+					return false
+				}
+			}
+			spaces = true
+		} else if is_break(value, i) {
+			if !breaks && value[i] == '\n' {
+				if !put_break(emitter) {
+					return false
+				}
+			}
+			if !write_break(emitter, value, &i) {
+				return false
+			}
+			emitter.indention = true
+			breaks = true
+		} else {
+			if breaks {
+				if !yaml_emitter_write_indent(emitter) {
+					return false
+				}
+			}
+			if value[i] == '\'' {
+				if !put(emitter, '\'') {
+					return false
+				}
+			}
+			if !write(emitter, value, &i) {
+				return false
+			}
+			emitter.indention = false
+			spaces = false
+			breaks = false
+		}
+	}
+	if !yaml_emitter_write_indicator(emitter, []byte{'\''}, false, false, false) {
+		return false
+	}
+	emitter.whitespace = false
+	emitter.indention = false
+	return true
+}
+
+func yaml_emitter_write_double_quoted_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool {
+	spaces := false
+	if !yaml_emitter_write_indicator(emitter, []byte{'"'}, true, false, false) {
+		return false
+	}
+
+	for i := 0; i < len(value); {
+		if !is_printable(value, i) || (!emitter.unicode && !is_ascii(value, i)) ||
+			is_bom(value, i) || is_break(value, i) ||
+			value[i] == '"' || value[i] == '\\' {
+
+			octet := value[i]
+
+			var w int
+			var v rune
+			switch {
+			case octet&0x80 == 0x00:
+				w, v = 1, rune(octet&0x7F)
+			case octet&0xE0 == 0xC0:
+				w, v = 2, rune(octet&0x1F)
+			case octet&0xF0 == 0xE0:
+				w, v = 3, rune(octet&0x0F)
+			case octet&0xF8 == 0xF0:
+				w, v = 4, rune(octet&0x07)
+			}
+			for k := 1; k < w; k++ {
+				octet = value[i+k]
+				v = (v << 6) + (rune(octet) & 0x3F)
+			}
+			i += w
+
+			if !put(emitter, '\\') {
+				return false
+			}
+
+			var ok bool
+			switch v {
+			case 0x00:
+				ok = put(emitter, '0')
+			case 0x07:
+				ok = put(emitter, 'a')
+			case 0x08:
+				ok = put(emitter, 'b')
+			case 0x09:
+				ok = put(emitter, 't')
+			case 0x0A:
+				ok = put(emitter, 'n')
+			case 0x0b:
+				ok = put(emitter, 'v')
+			case 0x0c:
+				ok = put(emitter, 'f')
+			case 0x0d:
+				ok = put(emitter, 'r')
+			case 0x1b:
+				ok = put(emitter, 'e')
+			case 0x22:
+				ok = put(emitter, '"')
+			case 0x5c:
+				ok = put(emitter, '\\')
+			case 0x85:
+				ok = put(emitter, 'N')
+			case 0xA0:
+				ok = put(emitter, '_')
+			case 0x2028:
+				ok = put(emitter, 'L')
+			case 0x2029:
+				ok = put(emitter, 'P')
+			default:
+				if v <= 0xFF {
+					ok = put(emitter, 'x')
+					w = 2
+				} else if v <= 0xFFFF {
+					ok = put(emitter, 'u')
+					w = 4
+				} else {
+					ok = put(emitter, 'U')
+					w = 8
+				}
+				for k := (w - 1) * 4; ok && k >= 0; k -= 4 {
+					digit := byte((v >> uint(k)) & 0x0F)
+					if digit < 10 {
+						ok = put(emitter, digit+'0')
+					} else {
+						ok = put(emitter, digit+'A'-10)
+					}
+				}
+			}
+			if !ok {
+				return false
+			}
+			spaces = false
+		} else if is_space(value, i) {
+			if allow_breaks && !spaces && emitter.column > emitter.best_width && i > 0 && i < len(value)-1 {
+				if !yaml_emitter_write_indent(emitter) {
+					return false
+				}
+				if is_space(value, i+1) {
+					if !put(emitter, '\\') {
+						return false
+					}
+				}
+				i += width(value[i])
+			} else if !write(emitter, value, &i) {
+				return false
+			}
+			spaces = true
+		} else {
+			if !write(emitter, value, &i) {
+				return false
+			}
+			spaces = false
+		}
+	}
+	if !yaml_emitter_write_indicator(emitter, []byte{'"'}, false, false, false) {
+		return false
+	}
+	emitter.whitespace = false
+	emitter.indention = false
+	return true
+}
+
+func yaml_emitter_write_block_scalar_hints(emitter *yaml_emitter_t, value []byte) bool {
+	if is_space(value, 0) || is_break(value, 0) {
+		indent_hint := []byte{'0' + byte(emitter.best_indent)}
+		if !yaml_emitter_write_indicator(emitter, indent_hint, false, false, false) {
+			return false
+		}
+	}
+
+	emitter.open_ended = false
+
+	var chomp_hint [1]byte
+	if len(value) == 0 {
+		chomp_hint[0] = '-'
+	} else {
+		i := len(value) - 1
+		for value[i]&0xC0 == 0x80 {
+			i--
+		}
+		if !is_break(value, i) {
+			chomp_hint[0] = '-'
+		} else if i == 0 {
+			chomp_hint[0] = '+'
+			emitter.open_ended = true
+		} else {
+			i--
+			for value[i]&0xC0 == 0x80 {
+				i--
+			}
+			if is_break(value, i) {
+				chomp_hint[0] = '+'
+				emitter.open_ended = true
+			}
+		}
+	}
+	if chomp_hint[0] != 0 {
+		if !yaml_emitter_write_indicator(emitter, chomp_hint[:], false, false, false) {
+			return false
+		}
+	}
+	return true
+}
+
+func yaml_emitter_write_literal_scalar(emitter *yaml_emitter_t, value []byte) bool {
+	if !yaml_emitter_write_indicator(emitter, []byte{'|'}, true, false, false) {
+		return false
+	}
+	if !yaml_emitter_write_block_scalar_hints(emitter, value) {
+		return false
+	}
+	if !put_break(emitter) {
+		return false
+	}
+	emitter.indention = true
+	emitter.whitespace = true
+	breaks := true
+	for i := 0; i < len(value); {
+		if is_break(value, i) {
+			if !write_break(emitter, value, &i) {
+				return false
+			}
+			emitter.indention = true
+			breaks = true
+		} else {
+			if breaks {
+				if !yaml_emitter_write_indent(emitter) {
+					return false
+				}
+			}
+			if !write(emitter, value, &i) {
+				return false
+			}
+			emitter.indention = false
+			breaks = false
+		}
+	}
+
+	return true
+}
+
+func yaml_emitter_write_folded_scalar(emitter *yaml_emitter_t, value []byte) bool {
+	if !yaml_emitter_write_indicator(emitter, []byte{'>'}, true, false, false) {
+		return false
+	}
+	if !yaml_emitter_write_block_scalar_hints(emitter, value) {
+		return false
+	}
+
+	if !put_break(emitter) {
+		return false
+	}
+	emitter.indention = true
+	emitter.whitespace = true
+
+	breaks := true
+	leading_spaces := true
+	for i := 0; i < len(value); {
+		if is_break(value, i) {
+			if !breaks && !leading_spaces && value[i] == '\n' {
+				k := 0
+				for is_break(value, k) {
+					k += width(value[k])
+				}
+				if !is_blankz(value, k) {
+					if !put_break(emitter) {
+						return false
+					}
+				}
+			}
+			if !write_break(emitter, value, &i) {
+				return false
+			}
+			emitter.indention = true
+			breaks = true
+		} else {
+			if breaks {
+				if !yaml_emitter_write_indent(emitter) {
+					return false
+				}
+				leading_spaces = is_blank(value, i)
+			}
+			if !breaks && is_space(value, i) && !is_space(value, i+1) && emitter.column > emitter.best_width {
+				if !yaml_emitter_write_indent(emitter) {
+					return false
+				}
+				i += width(value[i])
+			} else {
+				if !write(emitter, value, &i) {
+					return false
+				}
+			}
+			emitter.indention = false
+			breaks = false
+		}
+	}
+	return true
+}

+ 390 - 0
vendor/gopkg.in/yaml.v2/encode.go

@@ -0,0 +1,390 @@
+package yaml
+
+import (
+	"encoding"
+	"fmt"
+	"io"
+	"reflect"
+	"regexp"
+	"sort"
+	"strconv"
+	"strings"
+	"time"
+	"unicode/utf8"
+)
+
+// jsonNumber is the interface of the encoding/json.Number datatype.
+// Repeating the interface here avoids a dependency on encoding/json, and also
+// supports other libraries like jsoniter, which use a similar datatype with
+// the same interface. Detecting this interface is useful when dealing with
+// structures containing json.Number, which is a string under the hood. The
+// encoder should prefer the use of Int64(), Float64() and string(), in that
+// order, when encoding this type.
+type jsonNumber interface {
+	Float64() (float64, error)
+	Int64() (int64, error)
+	String() string
+}
+
+type encoder struct {
+	emitter yaml_emitter_t
+	event   yaml_event_t
+	out     []byte
+	flow    bool
+	// doneInit holds whether the initial stream_start_event has been
+	// emitted.
+	doneInit bool
+}
+
+func newEncoder() *encoder {
+	e := &encoder{}
+	yaml_emitter_initialize(&e.emitter)
+	yaml_emitter_set_output_string(&e.emitter, &e.out)
+	yaml_emitter_set_unicode(&e.emitter, true)
+	return e
+}
+
+func newEncoderWithWriter(w io.Writer) *encoder {
+	e := &encoder{}
+	yaml_emitter_initialize(&e.emitter)
+	yaml_emitter_set_output_writer(&e.emitter, w)
+	yaml_emitter_set_unicode(&e.emitter, true)
+	return e
+}
+
+func (e *encoder) init() {
+	if e.doneInit {
+		return
+	}
+	yaml_stream_start_event_initialize(&e.event, yaml_UTF8_ENCODING)
+	e.emit()
+	e.doneInit = true
+}
+
+func (e *encoder) finish() {
+	e.emitter.open_ended = false
+	yaml_stream_end_event_initialize(&e.event)
+	e.emit()
+}
+
+func (e *encoder) destroy() {
+	yaml_emitter_delete(&e.emitter)
+}
+
+func (e *encoder) emit() {
+	// This will internally delete the e.event value.
+	e.must(yaml_emitter_emit(&e.emitter, &e.event))
+}
+
+func (e *encoder) must(ok bool) {
+	if !ok {
+		msg := e.emitter.problem
+		if msg == "" {
+			msg = "unknown problem generating YAML content"
+		}
+		failf("%s", msg)
+	}
+}
+
+func (e *encoder) marshalDoc(tag string, in reflect.Value) {
+	e.init()
+	yaml_document_start_event_initialize(&e.event, nil, nil, true)
+	e.emit()
+	e.marshal(tag, in)
+	yaml_document_end_event_initialize(&e.event, true)
+	e.emit()
+}
+
+func (e *encoder) marshal(tag string, in reflect.Value) {
+	if !in.IsValid() || in.Kind() == reflect.Ptr && in.IsNil() {
+		e.nilv()
+		return
+	}
+	iface := in.Interface()
+	switch m := iface.(type) {
+	case jsonNumber:
+		integer, err := m.Int64()
+		if err == nil {
+			// In this case the json.Number is a valid int64
+			in = reflect.ValueOf(integer)
+			break
+		}
+		float, err := m.Float64()
+		if err == nil {
+			// In this case the json.Number is a valid float64
+			in = reflect.ValueOf(float)
+			break
+		}
+		// fallback case - no number could be obtained
+		in = reflect.ValueOf(m.String())
+	case time.Time, *time.Time:
+		// Although time.Time implements TextMarshaler,
+		// we don't want to treat it as a string for YAML
+		// purposes because YAML has special support for
+		// timestamps.
+	case Marshaler:
+		v, err := m.MarshalYAML()
+		if err != nil {
+			fail(err)
+		}
+		if v == nil {
+			e.nilv()
+			return
+		}
+		in = reflect.ValueOf(v)
+	case encoding.TextMarshaler:
+		text, err := m.MarshalText()
+		if err != nil {
+			fail(err)
+		}
+		in = reflect.ValueOf(string(text))
+	case nil:
+		e.nilv()
+		return
+	}
+	switch in.Kind() {
+	case reflect.Interface:
+		e.marshal(tag, in.Elem())
+	case reflect.Map:
+		e.mapv(tag, in)
+	case reflect.Ptr:
+		if in.Type() == ptrTimeType {
+			e.timev(tag, in.Elem())
+		} else {
+			e.marshal(tag, in.Elem())
+		}
+	case reflect.Struct:
+		if in.Type() == timeType {
+			e.timev(tag, in)
+		} else {
+			e.structv(tag, in)
+		}
+	case reflect.Slice, reflect.Array:
+		if in.Type().Elem() == mapItemType {
+			e.itemsv(tag, in)
+		} else {
+			e.slicev(tag, in)
+		}
+	case reflect.String:
+		e.stringv(tag, in)
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		if in.Type() == durationType {
+			e.stringv(tag, reflect.ValueOf(iface.(time.Duration).String()))
+		} else {
+			e.intv(tag, in)
+		}
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+		e.uintv(tag, in)
+	case reflect.Float32, reflect.Float64:
+		e.floatv(tag, in)
+	case reflect.Bool:
+		e.boolv(tag, in)
+	default:
+		panic("cannot marshal type: " + in.Type().String())
+	}
+}
+
+func (e *encoder) mapv(tag string, in reflect.Value) {
+	e.mappingv(tag, func() {
+		keys := keyList(in.MapKeys())
+		sort.Sort(keys)
+		for _, k := range keys {
+			e.marshal("", k)
+			e.marshal("", in.MapIndex(k))
+		}
+	})
+}
+
+func (e *encoder) itemsv(tag string, in reflect.Value) {
+	e.mappingv(tag, func() {
+		slice := in.Convert(reflect.TypeOf([]MapItem{})).Interface().([]MapItem)
+		for _, item := range slice {
+			e.marshal("", reflect.ValueOf(item.Key))
+			e.marshal("", reflect.ValueOf(item.Value))
+		}
+	})
+}
+
+func (e *encoder) structv(tag string, in reflect.Value) {
+	sinfo, err := getStructInfo(in.Type())
+	if err != nil {
+		panic(err)
+	}
+	e.mappingv(tag, func() {
+		for _, info := range sinfo.FieldsList {
+			var value reflect.Value
+			if info.Inline == nil {
+				value = in.Field(info.Num)
+			} else {
+				value = in.FieldByIndex(info.Inline)
+			}
+			if info.OmitEmpty && isZero(value) {
+				continue
+			}
+			e.marshal("", reflect.ValueOf(info.Key))
+			e.flow = info.Flow
+			e.marshal("", value)
+		}
+		if sinfo.InlineMap >= 0 {
+			m := in.Field(sinfo.InlineMap)
+			if m.Len() > 0 {
+				e.flow = false
+				keys := keyList(m.MapKeys())
+				sort.Sort(keys)
+				for _, k := range keys {
+					if _, found := sinfo.FieldsMap[k.String()]; found {
+						panic(fmt.Sprintf("Can't have key %q in inlined map; conflicts with struct field", k.String()))
+					}
+					e.marshal("", k)
+					e.flow = false
+					e.marshal("", m.MapIndex(k))
+				}
+			}
+		}
+	})
+}
+
+func (e *encoder) mappingv(tag string, f func()) {
+	implicit := tag == ""
+	style := yaml_BLOCK_MAPPING_STYLE
+	if e.flow {
+		e.flow = false
+		style = yaml_FLOW_MAPPING_STYLE
+	}
+	yaml_mapping_start_event_initialize(&e.event, nil, []byte(tag), implicit, style)
+	e.emit()
+	f()
+	yaml_mapping_end_event_initialize(&e.event)
+	e.emit()
+}
+
+func (e *encoder) slicev(tag string, in reflect.Value) {
+	implicit := tag == ""
+	style := yaml_BLOCK_SEQUENCE_STYLE
+	if e.flow {
+		e.flow = false
+		style = yaml_FLOW_SEQUENCE_STYLE
+	}
+	e.must(yaml_sequence_start_event_initialize(&e.event, nil, []byte(tag), implicit, style))
+	e.emit()
+	n := in.Len()
+	for i := 0; i < n; i++ {
+		e.marshal("", in.Index(i))
+	}
+	e.must(yaml_sequence_end_event_initialize(&e.event))
+	e.emit()
+}
+
+// isBase60 returns whether s is in base 60 notation as defined in YAML 1.1.
+//
+// The base 60 float notation in YAML 1.1 is a terrible idea and is unsupported
+// in YAML 1.2 and by this package, but these should be marshalled quoted for
+// the time being for compatibility with other parsers.
+func isBase60Float(s string) (result bool) {
+	// Fast path.
+	if s == "" {
+		return false
+	}
+	c := s[0]
+	if !(c == '+' || c == '-' || c >= '0' && c <= '9') || strings.IndexByte(s, ':') < 0 {
+		return false
+	}
+	// Do the full match.
+	return base60float.MatchString(s)
+}
+
+// From http://yaml.org/type/float.html, except the regular expression there
+// is bogus. In practice parsers do not enforce the "\.[0-9_]*" suffix.
+var base60float = regexp.MustCompile(`^[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+(?:\.[0-9_]*)?$`)
+
+func (e *encoder) stringv(tag string, in reflect.Value) {
+	var style yaml_scalar_style_t
+	s := in.String()
+	canUsePlain := true
+	switch {
+	case !utf8.ValidString(s):
+		if tag == yaml_BINARY_TAG {
+			failf("explicitly tagged !!binary data must be base64-encoded")
+		}
+		if tag != "" {
+			failf("cannot marshal invalid UTF-8 data as %s", shortTag(tag))
+		}
+		// It can't be encoded directly as YAML so use a binary tag
+		// and encode it as base64.
+		tag = yaml_BINARY_TAG
+		s = encodeBase64(s)
+	case tag == "":
+		// Check to see if it would resolve to a specific
+		// tag when encoded unquoted. If it doesn't,
+		// there's no need to quote it.
+		rtag, _ := resolve("", s)
+		canUsePlain = rtag == yaml_STR_TAG && !isBase60Float(s)
+	}
+	// Note: it's possible for user code to emit invalid YAML
+	// if they explicitly specify a tag and a string containing
+	// text that's incompatible with that tag.
+	switch {
+	case strings.Contains(s, "\n"):
+		style = yaml_LITERAL_SCALAR_STYLE
+	case canUsePlain:
+		style = yaml_PLAIN_SCALAR_STYLE
+	default:
+		style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
+	}
+	e.emitScalar(s, "", tag, style)
+}
+
+func (e *encoder) boolv(tag string, in reflect.Value) {
+	var s string
+	if in.Bool() {
+		s = "true"
+	} else {
+		s = "false"
+	}
+	e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE)
+}
+
+func (e *encoder) intv(tag string, in reflect.Value) {
+	s := strconv.FormatInt(in.Int(), 10)
+	e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE)
+}
+
+func (e *encoder) uintv(tag string, in reflect.Value) {
+	s := strconv.FormatUint(in.Uint(), 10)
+	e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE)
+}
+
+func (e *encoder) timev(tag string, in reflect.Value) {
+	t := in.Interface().(time.Time)
+	s := t.Format(time.RFC3339Nano)
+	e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE)
+}
+
+func (e *encoder) floatv(tag string, in reflect.Value) {
+	// Issue #352: When formatting, use the precision of the underlying value
+	precision := 64
+	if in.Kind() == reflect.Float32 {
+		precision = 32
+	}
+
+	s := strconv.FormatFloat(in.Float(), 'g', -1, precision)
+	switch s {
+	case "+Inf":
+		s = ".inf"
+	case "-Inf":
+		s = "-.inf"
+	case "NaN":
+		s = ".nan"
+	}
+	e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE)
+}
+
+func (e *encoder) nilv() {
+	e.emitScalar("null", "", "", yaml_PLAIN_SCALAR_STYLE)
+}
+
+func (e *encoder) emitScalar(value, anchor, tag string, style yaml_scalar_style_t) {
+	implicit := tag == ""
+	e.must(yaml_scalar_event_initialize(&e.event, []byte(anchor), []byte(tag), []byte(value), implicit, implicit, style))
+	e.emit()
+}

+ 5 - 0
vendor/gopkg.in/yaml.v2/go.mod

@@ -0,0 +1,5 @@
+module "gopkg.in/yaml.v2"
+
+require (
+	"gopkg.in/check.v1" v0.0.0-20161208181325-20d25e280405
+)

+ 1095 - 0
vendor/gopkg.in/yaml.v2/parserc.go

@@ -0,0 +1,1095 @@
+package yaml
+
+import (
+	"bytes"
+)
+
+// The parser implements the following grammar:
+//
+// stream               ::= STREAM-START implicit_document? explicit_document* STREAM-END
+// implicit_document    ::= block_node DOCUMENT-END*
+// explicit_document    ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
+// block_node_or_indentless_sequence    ::=
+//                          ALIAS
+//                          | properties (block_content | indentless_block_sequence)?
+//                          | block_content
+//                          | indentless_block_sequence
+// block_node           ::= ALIAS
+//                          | properties block_content?
+//                          | block_content
+// flow_node            ::= ALIAS
+//                          | properties flow_content?
+//                          | flow_content
+// properties           ::= TAG ANCHOR? | ANCHOR TAG?
+// block_content        ::= block_collection | flow_collection | SCALAR
+// flow_content         ::= flow_collection | SCALAR
+// block_collection     ::= block_sequence | block_mapping
+// flow_collection      ::= flow_sequence | flow_mapping
+// block_sequence       ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END
+// indentless_sequence  ::= (BLOCK-ENTRY block_node?)+
+// block_mapping        ::= BLOCK-MAPPING_START
+//                          ((KEY block_node_or_indentless_sequence?)?
+//                          (VALUE block_node_or_indentless_sequence?)?)*
+//                          BLOCK-END
+// flow_sequence        ::= FLOW-SEQUENCE-START
+//                          (flow_sequence_entry FLOW-ENTRY)*
+//                          flow_sequence_entry?
+//                          FLOW-SEQUENCE-END
+// flow_sequence_entry  ::= flow_node | KEY flow_node? (VALUE flow_node?)?
+// flow_mapping         ::= FLOW-MAPPING-START
+//                          (flow_mapping_entry FLOW-ENTRY)*
+//                          flow_mapping_entry?
+//                          FLOW-MAPPING-END
+// flow_mapping_entry   ::= flow_node | KEY flow_node? (VALUE flow_node?)?
+
+// Peek the next token in the token queue.
+func peek_token(parser *yaml_parser_t) *yaml_token_t {
+	if parser.token_available || yaml_parser_fetch_more_tokens(parser) {
+		return &parser.tokens[parser.tokens_head]
+	}
+	return nil
+}
+
+// Remove the next token from the queue (must be called after peek_token).
+func skip_token(parser *yaml_parser_t) {
+	parser.token_available = false
+	parser.tokens_parsed++
+	parser.stream_end_produced = parser.tokens[parser.tokens_head].typ == yaml_STREAM_END_TOKEN
+	parser.tokens_head++
+}
+
+// Get the next event.
+func yaml_parser_parse(parser *yaml_parser_t, event *yaml_event_t) bool {
+	// Erase the event object.
+	*event = yaml_event_t{}
+
+	// No events after the end of the stream or error.
+	if parser.stream_end_produced || parser.error != yaml_NO_ERROR || parser.state == yaml_PARSE_END_STATE {
+		return true
+	}
+
+	// Generate the next event.
+	return yaml_parser_state_machine(parser, event)
+}
+
+// Set parser error.
+func yaml_parser_set_parser_error(parser *yaml_parser_t, problem string, problem_mark yaml_mark_t) bool {
+	parser.error = yaml_PARSER_ERROR
+	parser.problem = problem
+	parser.problem_mark = problem_mark
+	return false
+}
+
+func yaml_parser_set_parser_error_context(parser *yaml_parser_t, context string, context_mark yaml_mark_t, problem string, problem_mark yaml_mark_t) bool {
+	parser.error = yaml_PARSER_ERROR
+	parser.context = context
+	parser.context_mark = context_mark
+	parser.problem = problem
+	parser.problem_mark = problem_mark
+	return false
+}
+
+// State dispatcher.
+func yaml_parser_state_machine(parser *yaml_parser_t, event *yaml_event_t) bool {
+	//trace("yaml_parser_state_machine", "state:", parser.state.String())
+
+	switch parser.state {
+	case yaml_PARSE_STREAM_START_STATE:
+		return yaml_parser_parse_stream_start(parser, event)
+
+	case yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE:
+		return yaml_parser_parse_document_start(parser, event, true)
+
+	case yaml_PARSE_DOCUMENT_START_STATE:
+		return yaml_parser_parse_document_start(parser, event, false)
+
+	case yaml_PARSE_DOCUMENT_CONTENT_STATE:
+		return yaml_parser_parse_document_content(parser, event)
+
+	case yaml_PARSE_DOCUMENT_END_STATE:
+		return yaml_parser_parse_document_end(parser, event)
+
+	case yaml_PARSE_BLOCK_NODE_STATE:
+		return yaml_parser_parse_node(parser, event, true, false)
+
+	case yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE:
+		return yaml_parser_parse_node(parser, event, true, true)
+
+	case yaml_PARSE_FLOW_NODE_STATE:
+		return yaml_parser_parse_node(parser, event, false, false)
+
+	case yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE:
+		return yaml_parser_parse_block_sequence_entry(parser, event, true)
+
+	case yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE:
+		return yaml_parser_parse_block_sequence_entry(parser, event, false)
+
+	case yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE:
+		return yaml_parser_parse_indentless_sequence_entry(parser, event)
+
+	case yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE:
+		return yaml_parser_parse_block_mapping_key(parser, event, true)
+
+	case yaml_PARSE_BLOCK_MAPPING_KEY_STATE:
+		return yaml_parser_parse_block_mapping_key(parser, event, false)
+
+	case yaml_PARSE_BLOCK_MAPPING_VALUE_STATE:
+		return yaml_parser_parse_block_mapping_value(parser, event)
+
+	case yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE:
+		return yaml_parser_parse_flow_sequence_entry(parser, event, true)
+
+	case yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE:
+		return yaml_parser_parse_flow_sequence_entry(parser, event, false)
+
+	case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE:
+		return yaml_parser_parse_flow_sequence_entry_mapping_key(parser, event)
+
+	case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE:
+		return yaml_parser_parse_flow_sequence_entry_mapping_value(parser, event)
+
+	case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE:
+		return yaml_parser_parse_flow_sequence_entry_mapping_end(parser, event)
+
+	case yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE:
+		return yaml_parser_parse_flow_mapping_key(parser, event, true)
+
+	case yaml_PARSE_FLOW_MAPPING_KEY_STATE:
+		return yaml_parser_parse_flow_mapping_key(parser, event, false)
+
+	case yaml_PARSE_FLOW_MAPPING_VALUE_STATE:
+		return yaml_parser_parse_flow_mapping_value(parser, event, false)
+
+	case yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE:
+		return yaml_parser_parse_flow_mapping_value(parser, event, true)
+
+	default:
+		panic("invalid parser state")
+	}
+}
+
+// Parse the production:
+// stream   ::= STREAM-START implicit_document? explicit_document* STREAM-END
+//              ************
+func yaml_parser_parse_stream_start(parser *yaml_parser_t, event *yaml_event_t) bool {
+	token := peek_token(parser)
+	if token == nil {
+		return false
+	}
+	if token.typ != yaml_STREAM_START_TOKEN {
+		return yaml_parser_set_parser_error(parser, "did not find expected <stream-start>", token.start_mark)
+	}
+	parser.state = yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE
+	*event = yaml_event_t{
+		typ:        yaml_STREAM_START_EVENT,
+		start_mark: token.start_mark,
+		end_mark:   token.end_mark,
+		encoding:   token.encoding,
+	}
+	skip_token(parser)
+	return true
+}
+
+// Parse the productions:
+// implicit_document    ::= block_node DOCUMENT-END*
+//                          *
+// explicit_document    ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
+//                          *************************
+func yaml_parser_parse_document_start(parser *yaml_parser_t, event *yaml_event_t, implicit bool) bool {
+
+	token := peek_token(parser)
+	if token == nil {
+		return false
+	}
+
+	// Parse extra document end indicators.
+	if !implicit {
+		for token.typ == yaml_DOCUMENT_END_TOKEN {
+			skip_token(parser)
+			token = peek_token(parser)
+			if token == nil {
+				return false
+			}
+		}
+	}
+
+	if implicit && token.typ != yaml_VERSION_DIRECTIVE_TOKEN &&
+		token.typ != yaml_TAG_DIRECTIVE_TOKEN &&
+		token.typ != yaml_DOCUMENT_START_TOKEN &&
+		token.typ != yaml_STREAM_END_TOKEN {
+		// Parse an implicit document.
+		if !yaml_parser_process_directives(parser, nil, nil) {
+			return false
+		}
+		parser.states = append(parser.states, yaml_PARSE_DOCUMENT_END_STATE)
+		parser.state = yaml_PARSE_BLOCK_NODE_STATE
+
+		*event = yaml_event_t{
+			typ:        yaml_DOCUMENT_START_EVENT,
+			start_mark: token.start_mark,
+			end_mark:   token.end_mark,
+		}
+
+	} else if token.typ != yaml_STREAM_END_TOKEN {
+		// Parse an explicit document.
+		var version_directive *yaml_version_directive_t
+		var tag_directives []yaml_tag_directive_t
+		start_mark := token.start_mark
+		if !yaml_parser_process_directives(parser, &version_directive, &tag_directives) {
+			return false
+		}
+		token = peek_token(parser)
+		if token == nil {
+			return false
+		}
+		if token.typ != yaml_DOCUMENT_START_TOKEN {
+			yaml_parser_set_parser_error(parser,
+				"did not find expected <document start>", token.start_mark)
+			return false
+		}
+		parser.states = append(parser.states, yaml_PARSE_DOCUMENT_END_STATE)
+		parser.state = yaml_PARSE_DOCUMENT_CONTENT_STATE
+		end_mark := token.end_mark
+
+		*event = yaml_event_t{
+			typ:               yaml_DOCUMENT_START_EVENT,
+			start_mark:        start_mark,
+			end_mark:          end_mark,
+			version_directive: version_directive,
+			tag_directives:    tag_directives,
+			implicit:          false,
+		}
+		skip_token(parser)
+
+	} else {
+		// Parse the stream end.
+		parser.state = yaml_PARSE_END_STATE
+		*event = yaml_event_t{
+			typ:        yaml_STREAM_END_EVENT,
+			start_mark: token.start_mark,
+			end_mark:   token.end_mark,
+		}
+		skip_token(parser)
+	}
+
+	return true
+}
+
+// Parse the productions:
+// explicit_document    ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
+//                                                    ***********
+//
+func yaml_parser_parse_document_content(parser *yaml_parser_t, event *yaml_event_t) bool {
+	token := peek_token(parser)
+	if token == nil {
+		return false
+	}
+	if token.typ == yaml_VERSION_DIRECTIVE_TOKEN ||
+		token.typ == yaml_TAG_DIRECTIVE_TOKEN ||
+		token.typ == yaml_DOCUMENT_START_TOKEN ||
+		token.typ == yaml_DOCUMENT_END_TOKEN ||
+		token.typ == yaml_STREAM_END_TOKEN {
+		parser.state = parser.states[len(parser.states)-1]
+		parser.states = parser.states[:len(parser.states)-1]
+		return yaml_parser_process_empty_scalar(parser, event,
+			token.start_mark)
+	}
+	return yaml_parser_parse_node(parser, event, true, false)
+}
+
+// Parse the productions:
+// implicit_document    ::= block_node DOCUMENT-END*
+//                                     *************
+// explicit_document    ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
+//
+func yaml_parser_parse_document_end(parser *yaml_parser_t, event *yaml_event_t) bool {
+	token := peek_token(parser)
+	if token == nil {
+		return false
+	}
+
+	start_mark := token.start_mark
+	end_mark := token.start_mark
+
+	implicit := true
+	if token.typ == yaml_DOCUMENT_END_TOKEN {
+		end_mark = token.end_mark
+		skip_token(parser)
+		implicit = false
+	}
+
+	parser.tag_directives = parser.tag_directives[:0]
+
+	parser.state = yaml_PARSE_DOCUMENT_START_STATE
+	*event = yaml_event_t{
+		typ:        yaml_DOCUMENT_END_EVENT,
+		start_mark: start_mark,
+		end_mark:   end_mark,
+		implicit:   implicit,
+	}
+	return true
+}
+
+// Parse the productions:
+// block_node_or_indentless_sequence    ::=
+//                          ALIAS
+//                          *****
+//                          | properties (block_content | indentless_block_sequence)?
+//                            **********  *
+//                          | block_content | indentless_block_sequence
+//                            *
+// block_node           ::= ALIAS
+//                          *****
+//                          | properties block_content?
+//                            ********** *
+//                          | block_content
+//                            *
+// flow_node            ::= ALIAS
+//                          *****
+//                          | properties flow_content?
+//                            ********** *
+//                          | flow_content
+//                            *
+// properties           ::= TAG ANCHOR? | ANCHOR TAG?
+//                          *************************
+// block_content        ::= block_collection | flow_collection | SCALAR
+//                                                               ******
+// flow_content         ::= flow_collection | SCALAR
+//                                            ******
+func yaml_parser_parse_node(parser *yaml_parser_t, event *yaml_event_t, block, indentless_sequence bool) bool {
+	//defer trace("yaml_parser_parse_node", "block:", block, "indentless_sequence:", indentless_sequence)()
+
+	token := peek_token(parser)
+	if token == nil {
+		return false
+	}
+
+	if token.typ == yaml_ALIAS_TOKEN {
+		parser.state = parser.states[len(parser.states)-1]
+		parser.states = parser.states[:len(parser.states)-1]
+		*event = yaml_event_t{
+			typ:        yaml_ALIAS_EVENT,
+			start_mark: token.start_mark,
+			end_mark:   token.end_mark,
+			anchor:     token.value,
+		}
+		skip_token(parser)
+		return true
+	}
+
+	start_mark := token.start_mark
+	end_mark := token.start_mark
+
+	var tag_token bool
+	var tag_handle, tag_suffix, anchor []byte
+	var tag_mark yaml_mark_t
+	if token.typ == yaml_ANCHOR_TOKEN {
+		anchor = token.value
+		start_mark = token.start_mark
+		end_mark = token.end_mark
+		skip_token(parser)
+		token = peek_token(parser)
+		if token == nil {
+			return false
+		}
+		if token.typ == yaml_TAG_TOKEN {
+			tag_token = true
+			tag_handle = token.value
+			tag_suffix = token.suffix
+			tag_mark = token.start_mark
+			end_mark = token.end_mark
+			skip_token(parser)
+			token = peek_token(parser)
+			if token == nil {
+				return false
+			}
+		}
+	} else if token.typ == yaml_TAG_TOKEN {
+		tag_token = true
+		tag_handle = token.value
+		tag_suffix = token.suffix
+		start_mark = token.start_mark
+		tag_mark = token.start_mark
+		end_mark = token.end_mark
+		skip_token(parser)
+		token = peek_token(parser)
+		if token == nil {
+			return false
+		}
+		if token.typ == yaml_ANCHOR_TOKEN {
+			anchor = token.value
+			end_mark = token.end_mark
+			skip_token(parser)
+			token = peek_token(parser)
+			if token == nil {
+				return false
+			}
+		}
+	}
+
+	var tag []byte
+	if tag_token {
+		if len(tag_handle) == 0 {
+			tag = tag_suffix
+			tag_suffix = nil
+		} else {
+			for i := range parser.tag_directives {
+				if bytes.Equal(parser.tag_directives[i].handle, tag_handle) {
+					tag = append([]byte(nil), parser.tag_directives[i].prefix...)
+					tag = append(tag, tag_suffix...)
+					break
+				}
+			}
+			if len(tag) == 0 {
+				yaml_parser_set_parser_error_context(parser,
+					"while parsing a node", start_mark,
+					"found undefined tag handle", tag_mark)
+				return false
+			}
+		}
+	}
+
+	implicit := len(tag) == 0
+	if indentless_sequence && token.typ == yaml_BLOCK_ENTRY_TOKEN {
+		end_mark = token.end_mark
+		parser.state = yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE
+		*event = yaml_event_t{
+			typ:        yaml_SEQUENCE_START_EVENT,
+			start_mark: start_mark,
+			end_mark:   end_mark,
+			anchor:     anchor,
+			tag:        tag,
+			implicit:   implicit,
+			style:      yaml_style_t(yaml_BLOCK_SEQUENCE_STYLE),
+		}
+		return true
+	}
+	if token.typ == yaml_SCALAR_TOKEN {
+		var plain_implicit, quoted_implicit bool
+		end_mark = token.end_mark
+		if (len(tag) == 0 && token.style == yaml_PLAIN_SCALAR_STYLE) || (len(tag) == 1 && tag[0] == '!') {
+			plain_implicit = true
+		} else if len(tag) == 0 {
+			quoted_implicit = true
+		}
+		parser.state = parser.states[len(parser.states)-1]
+		parser.states = parser.states[:len(parser.states)-1]
+
+		*event = yaml_event_t{
+			typ:             yaml_SCALAR_EVENT,
+			start_mark:      start_mark,
+			end_mark:        end_mark,
+			anchor:          anchor,
+			tag:             tag,
+			value:           token.value,
+			implicit:        plain_implicit,
+			quoted_implicit: quoted_implicit,
+			style:           yaml_style_t(token.style),
+		}
+		skip_token(parser)
+		return true
+	}
+	if token.typ == yaml_FLOW_SEQUENCE_START_TOKEN {
+		// [Go] Some of the events below can be merged as they differ only on style.
+		end_mark = token.end_mark
+		parser.state = yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE
+		*event = yaml_event_t{
+			typ:        yaml_SEQUENCE_START_EVENT,
+			start_mark: start_mark,
+			end_mark:   end_mark,
+			anchor:     anchor,
+			tag:        tag,
+			implicit:   implicit,
+			style:      yaml_style_t(yaml_FLOW_SEQUENCE_STYLE),
+		}
+		return true
+	}
+	if token.typ == yaml_FLOW_MAPPING_START_TOKEN {
+		end_mark = token.end_mark
+		parser.state = yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE
+		*event = yaml_event_t{
+			typ:        yaml_MAPPING_START_EVENT,
+			start_mark: start_mark,
+			end_mark:   end_mark,
+			anchor:     anchor,
+			tag:        tag,
+			implicit:   implicit,
+			style:      yaml_style_t(yaml_FLOW_MAPPING_STYLE),
+		}
+		return true
+	}
+	if block && token.typ == yaml_BLOCK_SEQUENCE_START_TOKEN {
+		end_mark = token.end_mark
+		parser.state = yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE
+		*event = yaml_event_t{
+			typ:        yaml_SEQUENCE_START_EVENT,
+			start_mark: start_mark,
+			end_mark:   end_mark,
+			anchor:     anchor,
+			tag:        tag,
+			implicit:   implicit,
+			style:      yaml_style_t(yaml_BLOCK_SEQUENCE_STYLE),
+		}
+		return true
+	}
+	if block && token.typ == yaml_BLOCK_MAPPING_START_TOKEN {
+		end_mark = token.end_mark
+		parser.state = yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE
+		*event = yaml_event_t{
+			typ:        yaml_MAPPING_START_EVENT,
+			start_mark: start_mark,
+			end_mark:   end_mark,
+			anchor:     anchor,
+			tag:        tag,
+			implicit:   implicit,
+			style:      yaml_style_t(yaml_BLOCK_MAPPING_STYLE),
+		}
+		return true
+	}
+	if len(anchor) > 0 || len(tag) > 0 {
+		parser.state = parser.states[len(parser.states)-1]
+		parser.states = parser.states[:len(parser.states)-1]
+
+		*event = yaml_event_t{
+			typ:             yaml_SCALAR_EVENT,
+			start_mark:      start_mark,
+			end_mark:        end_mark,
+			anchor:          anchor,
+			tag:             tag,
+			implicit:        implicit,
+			quoted_implicit: false,
+			style:           yaml_style_t(yaml_PLAIN_SCALAR_STYLE),
+		}
+		return true
+	}
+
+	context := "while parsing a flow node"
+	if block {
+		context = "while parsing a block node"
+	}
+	yaml_parser_set_parser_error_context(parser, context, start_mark,
+		"did not find expected node content", token.start_mark)
+	return false
+}
+
+// Parse the productions:
+// block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END
+//                    ********************  *********** *             *********
+//
+func yaml_parser_parse_block_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {
+	if first {
+		token := peek_token(parser)
+		parser.marks = append(parser.marks, token.start_mark)
+		skip_token(parser)
+	}
+
+	token := peek_token(parser)
+	if token == nil {
+		return false
+	}
+
+	if token.typ == yaml_BLOCK_ENTRY_TOKEN {
+		mark := token.end_mark
+		skip_token(parser)
+		token = peek_token(parser)
+		if token == nil {
+			return false
+		}
+		if token.typ != yaml_BLOCK_ENTRY_TOKEN && token.typ != yaml_BLOCK_END_TOKEN {
+			parser.states = append(parser.states, yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE)
+			return yaml_parser_parse_node(parser, event, true, false)
+		} else {
+			parser.state = yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE
+			return yaml_parser_process_empty_scalar(parser, event, mark)
+		}
+	}
+	if token.typ == yaml_BLOCK_END_TOKEN {
+		parser.state = parser.states[len(parser.states)-1]
+		parser.states = parser.states[:len(parser.states)-1]
+		parser.marks = parser.marks[:len(parser.marks)-1]
+
+		*event = yaml_event_t{
+			typ:        yaml_SEQUENCE_END_EVENT,
+			start_mark: token.start_mark,
+			end_mark:   token.end_mark,
+		}
+
+		skip_token(parser)
+		return true
+	}
+
+	context_mark := parser.marks[len(parser.marks)-1]
+	parser.marks = parser.marks[:len(parser.marks)-1]
+	return yaml_parser_set_parser_error_context(parser,
+		"while parsing a block collection", context_mark,
+		"did not find expected '-' indicator", token.start_mark)
+}
+
+// Parse the productions:
+// indentless_sequence  ::= (BLOCK-ENTRY block_node?)+
+//                           *********** *
+func yaml_parser_parse_indentless_sequence_entry(parser *yaml_parser_t, event *yaml_event_t) bool {
+	token := peek_token(parser)
+	if token == nil {
+		return false
+	}
+
+	if token.typ == yaml_BLOCK_ENTRY_TOKEN {
+		mark := token.end_mark
+		skip_token(parser)
+		token = peek_token(parser)
+		if token == nil {
+			return false
+		}
+		if token.typ != yaml_BLOCK_ENTRY_TOKEN &&
+			token.typ != yaml_KEY_TOKEN &&
+			token.typ != yaml_VALUE_TOKEN &&
+			token.typ != yaml_BLOCK_END_TOKEN {
+			parser.states = append(parser.states, yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE)
+			return yaml_parser_parse_node(parser, event, true, false)
+		}
+		parser.state = yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE
+		return yaml_parser_process_empty_scalar(parser, event, mark)
+	}
+	parser.state = parser.states[len(parser.states)-1]
+	parser.states = parser.states[:len(parser.states)-1]
+
+	*event = yaml_event_t{
+		typ:        yaml_SEQUENCE_END_EVENT,
+		start_mark: token.start_mark,
+		end_mark:   token.start_mark, // [Go] Shouldn't this be token.end_mark?
+	}
+	return true
+}
+
+// Parse the productions:
+// block_mapping        ::= BLOCK-MAPPING_START
+//                          *******************
+//                          ((KEY block_node_or_indentless_sequence?)?
+//                            *** *
+//                          (VALUE block_node_or_indentless_sequence?)?)*
+//
+//                          BLOCK-END
+//                          *********
+//
+func yaml_parser_parse_block_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {
+	if first {
+		token := peek_token(parser)
+		parser.marks = append(parser.marks, token.start_mark)
+		skip_token(parser)
+	}
+
+	token := peek_token(parser)
+	if token == nil {
+		return false
+	}
+
+	if token.typ == yaml_KEY_TOKEN {
+		mark := token.end_mark
+		skip_token(parser)
+		token = peek_token(parser)
+		if token == nil {
+			return false
+		}
+		if token.typ != yaml_KEY_TOKEN &&
+			token.typ != yaml_VALUE_TOKEN &&
+			token.typ != yaml_BLOCK_END_TOKEN {
+			parser.states = append(parser.states, yaml_PARSE_BLOCK_MAPPING_VALUE_STATE)
+			return yaml_parser_parse_node(parser, event, true, true)
+		} else {
+			parser.state = yaml_PARSE_BLOCK_MAPPING_VALUE_STATE
+			return yaml_parser_process_empty_scalar(parser, event, mark)
+		}
+	} else if token.typ == yaml_BLOCK_END_TOKEN {
+		parser.state = parser.states[len(parser.states)-1]
+		parser.states = parser.states[:len(parser.states)-1]
+		parser.marks = parser.marks[:len(parser.marks)-1]
+		*event = yaml_event_t{
+			typ:        yaml_MAPPING_END_EVENT,
+			start_mark: token.start_mark,
+			end_mark:   token.end_mark,
+		}
+		skip_token(parser)
+		return true
+	}
+
+	context_mark := parser.marks[len(parser.marks)-1]
+	parser.marks = parser.marks[:len(parser.marks)-1]
+	return yaml_parser_set_parser_error_context(parser,
+		"while parsing a block mapping", context_mark,
+		"did not find expected key", token.start_mark)
+}
+
+// Parse the productions:
+// block_mapping        ::= BLOCK-MAPPING_START
+//
+//                          ((KEY block_node_or_indentless_sequence?)?
+//
+//                          (VALUE block_node_or_indentless_sequence?)?)*
+//                           ***** *
+//                          BLOCK-END
+//
+//
+func yaml_parser_parse_block_mapping_value(parser *yaml_parser_t, event *yaml_event_t) bool {
+	token := peek_token(parser)
+	if token == nil {
+		return false
+	}
+	if token.typ == yaml_VALUE_TOKEN {
+		mark := token.end_mark
+		skip_token(parser)
+		token = peek_token(parser)
+		if token == nil {
+			return false
+		}
+		if token.typ != yaml_KEY_TOKEN &&
+			token.typ != yaml_VALUE_TOKEN &&
+			token.typ != yaml_BLOCK_END_TOKEN {
+			parser.states = append(parser.states, yaml_PARSE_BLOCK_MAPPING_KEY_STATE)
+			return yaml_parser_parse_node(parser, event, true, true)
+		}
+		parser.state = yaml_PARSE_BLOCK_MAPPING_KEY_STATE
+		return yaml_parser_process_empty_scalar(parser, event, mark)
+	}
+	parser.state = yaml_PARSE_BLOCK_MAPPING_KEY_STATE
+	return yaml_parser_process_empty_scalar(parser, event, token.start_mark)
+}
+
+// Parse the productions:
+// flow_sequence        ::= FLOW-SEQUENCE-START
+//                          *******************
+//                          (flow_sequence_entry FLOW-ENTRY)*
+//                           *                   **********
+//                          flow_sequence_entry?
+//                          *
+//                          FLOW-SEQUENCE-END
+//                          *****************
+// flow_sequence_entry  ::= flow_node | KEY flow_node? (VALUE flow_node?)?
+//                          *
+//
+func yaml_parser_parse_flow_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {
+	if first {
+		token := peek_token(parser)
+		parser.marks = append(parser.marks, token.start_mark)
+		skip_token(parser)
+	}
+	token := peek_token(parser)
+	if token == nil {
+		return false
+	}
+	if token.typ != yaml_FLOW_SEQUENCE_END_TOKEN {
+		if !first {
+			if token.typ == yaml_FLOW_ENTRY_TOKEN {
+				skip_token(parser)
+				token = peek_token(parser)
+				if token == nil {
+					return false
+				}
+			} else {
+				context_mark := parser.marks[len(parser.marks)-1]
+				parser.marks = parser.marks[:len(parser.marks)-1]
+				return yaml_parser_set_parser_error_context(parser,
+					"while parsing a flow sequence", context_mark,
+					"did not find expected ',' or ']'", token.start_mark)
+			}
+		}
+
+		if token.typ == yaml_KEY_TOKEN {
+			parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE
+			*event = yaml_event_t{
+				typ:        yaml_MAPPING_START_EVENT,
+				start_mark: token.start_mark,
+				end_mark:   token.end_mark,
+				implicit:   true,
+				style:      yaml_style_t(yaml_FLOW_MAPPING_STYLE),
+			}
+			skip_token(parser)
+			return true
+		} else if token.typ != yaml_FLOW_SEQUENCE_END_TOKEN {
+			parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE)
+			return yaml_parser_parse_node(parser, event, false, false)
+		}
+	}
+
+	parser.state = parser.states[len(parser.states)-1]
+	parser.states = parser.states[:len(parser.states)-1]
+	parser.marks = parser.marks[:len(parser.marks)-1]
+
+	*event = yaml_event_t{
+		typ:        yaml_SEQUENCE_END_EVENT,
+		start_mark: token.start_mark,
+		end_mark:   token.end_mark,
+	}
+
+	skip_token(parser)
+	return true
+}
+
+//
+// Parse the productions:
+// flow_sequence_entry  ::= flow_node | KEY flow_node? (VALUE flow_node?)?
+//                                      *** *
+//
+func yaml_parser_parse_flow_sequence_entry_mapping_key(parser *yaml_parser_t, event *yaml_event_t) bool {
+	token := peek_token(parser)
+	if token == nil {
+		return false
+	}
+	if token.typ != yaml_VALUE_TOKEN &&
+		token.typ != yaml_FLOW_ENTRY_TOKEN &&
+		token.typ != yaml_FLOW_SEQUENCE_END_TOKEN {
+		parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE)
+		return yaml_parser_parse_node(parser, event, false, false)
+	}
+	mark := token.end_mark
+	skip_token(parser)
+	parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE
+	return yaml_parser_process_empty_scalar(parser, event, mark)
+}
+
+// Parse the productions:
+// flow_sequence_entry  ::= flow_node | KEY flow_node? (VALUE flow_node?)?
+//                                                      ***** *
+//
+func yaml_parser_parse_flow_sequence_entry_mapping_value(parser *yaml_parser_t, event *yaml_event_t) bool {
+	token := peek_token(parser)
+	if token == nil {
+		return false
+	}
+	if token.typ == yaml_VALUE_TOKEN {
+		skip_token(parser)
+		token := peek_token(parser)
+		if token == nil {
+			return false
+		}
+		if token.typ != yaml_FLOW_ENTRY_TOKEN && token.typ != yaml_FLOW_SEQUENCE_END_TOKEN {
+			parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE)
+			return yaml_parser_parse_node(parser, event, false, false)
+		}
+	}
+	parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE
+	return yaml_parser_process_empty_scalar(parser, event, token.start_mark)
+}
+
+// Parse the productions:
+// flow_sequence_entry  ::= flow_node | KEY flow_node? (VALUE flow_node?)?
+//                                                                      *
+//
+func yaml_parser_parse_flow_sequence_entry_mapping_end(parser *yaml_parser_t, event *yaml_event_t) bool {
+	token := peek_token(parser)
+	if token == nil {
+		return false
+	}
+	parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE
+	*event = yaml_event_t{
+		typ:        yaml_MAPPING_END_EVENT,
+		start_mark: token.start_mark,
+		end_mark:   token.start_mark, // [Go] Shouldn't this be end_mark?
+	}
+	return true
+}
+
+// Parse the productions:
+// flow_mapping         ::= FLOW-MAPPING-START
+//                          ******************
+//                          (flow_mapping_entry FLOW-ENTRY)*
+//                           *                  **********
+//                          flow_mapping_entry?
+//                          ******************
+//                          FLOW-MAPPING-END
+//                          ****************
+// flow_mapping_entry   ::= flow_node | KEY flow_node? (VALUE flow_node?)?
+//                          *           *** *
+//
+func yaml_parser_parse_flow_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {
+	if first {
+		token := peek_token(parser)
+		parser.marks = append(parser.marks, token.start_mark)
+		skip_token(parser)
+	}
+
+	token := peek_token(parser)
+	if token == nil {
+		return false
+	}
+
+	if token.typ != yaml_FLOW_MAPPING_END_TOKEN {
+		if !first {
+			if token.typ == yaml_FLOW_ENTRY_TOKEN {
+				skip_token(parser)
+				token = peek_token(parser)
+				if token == nil {
+					return false
+				}
+			} else {
+				context_mark := parser.marks[len(parser.marks)-1]
+				parser.marks = parser.marks[:len(parser.marks)-1]
+				return yaml_parser_set_parser_error_context(parser,
+					"while parsing a flow mapping", context_mark,
+					"did not find expected ',' or '}'", token.start_mark)
+			}
+		}
+
+		if token.typ == yaml_KEY_TOKEN {
+			skip_token(parser)
+			token = peek_token(parser)
+			if token == nil {
+				return false
+			}
+			if token.typ != yaml_VALUE_TOKEN &&
+				token.typ != yaml_FLOW_ENTRY_TOKEN &&
+				token.typ != yaml_FLOW_MAPPING_END_TOKEN {
+				parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_VALUE_STATE)
+				return yaml_parser_parse_node(parser, event, false, false)
+			} else {
+				parser.state = yaml_PARSE_FLOW_MAPPING_VALUE_STATE
+				return yaml_parser_process_empty_scalar(parser, event, token.start_mark)
+			}
+		} else if token.typ != yaml_FLOW_MAPPING_END_TOKEN {
+			parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE)
+			return yaml_parser_parse_node(parser, event, false, false)
+		}
+	}
+
+	parser.state = parser.states[len(parser.states)-1]
+	parser.states = parser.states[:len(parser.states)-1]
+	parser.marks = parser.marks[:len(parser.marks)-1]
+	*event = yaml_event_t{
+		typ:        yaml_MAPPING_END_EVENT,
+		start_mark: token.start_mark,
+		end_mark:   token.end_mark,
+	}
+	skip_token(parser)
+	return true
+}
+
+// Parse the productions:
+// flow_mapping_entry   ::= flow_node | KEY flow_node? (VALUE flow_node?)?
+//                                   *                  ***** *
+//
+func yaml_parser_parse_flow_mapping_value(parser *yaml_parser_t, event *yaml_event_t, empty bool) bool {
+	token := peek_token(parser)
+	if token == nil {
+		return false
+	}
+	if empty {
+		parser.state = yaml_PARSE_FLOW_MAPPING_KEY_STATE
+		return yaml_parser_process_empty_scalar(parser, event, token.start_mark)
+	}
+	if token.typ == yaml_VALUE_TOKEN {
+		skip_token(parser)
+		token = peek_token(parser)
+		if token == nil {
+			return false
+		}
+		if token.typ != yaml_FLOW_ENTRY_TOKEN && token.typ != yaml_FLOW_MAPPING_END_TOKEN {
+			parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_KEY_STATE)
+			return yaml_parser_parse_node(parser, event, false, false)
+		}
+	}
+	parser.state = yaml_PARSE_FLOW_MAPPING_KEY_STATE
+	return yaml_parser_process_empty_scalar(parser, event, token.start_mark)
+}
+
+// Generate an empty scalar event.
+func yaml_parser_process_empty_scalar(parser *yaml_parser_t, event *yaml_event_t, mark yaml_mark_t) bool {
+	*event = yaml_event_t{
+		typ:        yaml_SCALAR_EVENT,
+		start_mark: mark,
+		end_mark:   mark,
+		value:      nil, // Empty
+		implicit:   true,
+		style:      yaml_style_t(yaml_PLAIN_SCALAR_STYLE),
+	}
+	return true
+}
+
+var default_tag_directives = []yaml_tag_directive_t{
+	{[]byte("!"), []byte("!")},
+	{[]byte("!!"), []byte("tag:yaml.org,2002:")},
+}
+
+// Parse directives.
+func yaml_parser_process_directives(parser *yaml_parser_t,
+	version_directive_ref **yaml_version_directive_t,
+	tag_directives_ref *[]yaml_tag_directive_t) bool {
+
+	var version_directive *yaml_version_directive_t
+	var tag_directives []yaml_tag_directive_t
+
+	token := peek_token(parser)
+	if token == nil {
+		return false
+	}
+
+	for token.typ == yaml_VERSION_DIRECTIVE_TOKEN || token.typ == yaml_TAG_DIRECTIVE_TOKEN {
+		if token.typ == yaml_VERSION_DIRECTIVE_TOKEN {
+			if version_directive != nil {
+				yaml_parser_set_parser_error(parser,
+					"found duplicate %YAML directive", token.start_mark)
+				return false
+			}
+			if token.major != 1 || token.minor != 1 {
+				yaml_parser_set_parser_error(parser,
+					"found incompatible YAML document", token.start_mark)
+				return false
+			}
+			version_directive = &yaml_version_directive_t{
+				major: token.major,
+				minor: token.minor,
+			}
+		} else if token.typ == yaml_TAG_DIRECTIVE_TOKEN {
+			value := yaml_tag_directive_t{
+				handle: token.value,
+				prefix: token.prefix,
+			}
+			if !yaml_parser_append_tag_directive(parser, value, false, token.start_mark) {
+				return false
+			}
+			tag_directives = append(tag_directives, value)
+		}
+
+		skip_token(parser)
+		token = peek_token(parser)
+		if token == nil {
+			return false
+		}
+	}
+
+	for i := range default_tag_directives {
+		if !yaml_parser_append_tag_directive(parser, default_tag_directives[i], true, token.start_mark) {
+			return false
+		}
+	}
+
+	if version_directive_ref != nil {
+		*version_directive_ref = version_directive
+	}
+	if tag_directives_ref != nil {
+		*tag_directives_ref = tag_directives
+	}
+	return true
+}
+
+// Append a tag directive to the directives stack.
+func yaml_parser_append_tag_directive(parser *yaml_parser_t, value yaml_tag_directive_t, allow_duplicates bool, mark yaml_mark_t) bool {
+	for i := range parser.tag_directives {
+		if bytes.Equal(value.handle, parser.tag_directives[i].handle) {
+			if allow_duplicates {
+				return true
+			}
+			return yaml_parser_set_parser_error(parser, "found duplicate %TAG directive", mark)
+		}
+	}
+
+	// [Go] I suspect the copy is unnecessary. This was likely done
+	// because there was no way to track ownership of the data.
+	value_copy := yaml_tag_directive_t{
+		handle: make([]byte, len(value.handle)),
+		prefix: make([]byte, len(value.prefix)),
+	}
+	copy(value_copy.handle, value.handle)
+	copy(value_copy.prefix, value.prefix)
+	parser.tag_directives = append(parser.tag_directives, value_copy)
+	return true
+}

+ 412 - 0
vendor/gopkg.in/yaml.v2/readerc.go

@@ -0,0 +1,412 @@
+package yaml
+
+import (
+	"io"
+)
+
+// Set the reader error and return 0.
+func yaml_parser_set_reader_error(parser *yaml_parser_t, problem string, offset int, value int) bool {
+	parser.error = yaml_READER_ERROR
+	parser.problem = problem
+	parser.problem_offset = offset
+	parser.problem_value = value
+	return false
+}
+
+// Byte order marks.
+const (
+	bom_UTF8    = "\xef\xbb\xbf"
+	bom_UTF16LE = "\xff\xfe"
+	bom_UTF16BE = "\xfe\xff"
+)
+
+// Determine the input stream encoding by checking the BOM symbol. If no BOM is
+// found, the UTF-8 encoding is assumed. Return 1 on success, 0 on failure.
+func yaml_parser_determine_encoding(parser *yaml_parser_t) bool {
+	// Ensure that we had enough bytes in the raw buffer.
+	for !parser.eof && len(parser.raw_buffer)-parser.raw_buffer_pos < 3 {
+		if !yaml_parser_update_raw_buffer(parser) {
+			return false
+		}
+	}
+
+	// Determine the encoding.
+	buf := parser.raw_buffer
+	pos := parser.raw_buffer_pos
+	avail := len(buf) - pos
+	if avail >= 2 && buf[pos] == bom_UTF16LE[0] && buf[pos+1] == bom_UTF16LE[1] {
+		parser.encoding = yaml_UTF16LE_ENCODING
+		parser.raw_buffer_pos += 2
+		parser.offset += 2
+	} else if avail >= 2 && buf[pos] == bom_UTF16BE[0] && buf[pos+1] == bom_UTF16BE[1] {
+		parser.encoding = yaml_UTF16BE_ENCODING
+		parser.raw_buffer_pos += 2
+		parser.offset += 2
+	} else if avail >= 3 && buf[pos] == bom_UTF8[0] && buf[pos+1] == bom_UTF8[1] && buf[pos+2] == bom_UTF8[2] {
+		parser.encoding = yaml_UTF8_ENCODING
+		parser.raw_buffer_pos += 3
+		parser.offset += 3
+	} else {
+		parser.encoding = yaml_UTF8_ENCODING
+	}
+	return true
+}
+
+// Update the raw buffer.
+func yaml_parser_update_raw_buffer(parser *yaml_parser_t) bool {
+	size_read := 0
+
+	// Return if the raw buffer is full.
+	if parser.raw_buffer_pos == 0 && len(parser.raw_buffer) == cap(parser.raw_buffer) {
+		return true
+	}
+
+	// Return on EOF.
+	if parser.eof {
+		return true
+	}
+
+	// Move the remaining bytes in the raw buffer to the beginning.
+	if parser.raw_buffer_pos > 0 && parser.raw_buffer_pos < len(parser.raw_buffer) {
+		copy(parser.raw_buffer, parser.raw_buffer[parser.raw_buffer_pos:])
+	}
+	parser.raw_buffer = parser.raw_buffer[:len(parser.raw_buffer)-parser.raw_buffer_pos]
+	parser.raw_buffer_pos = 0
+
+	// Call the read handler to fill the buffer.
+	size_read, err := parser.read_handler(parser, parser.raw_buffer[len(parser.raw_buffer):cap(parser.raw_buffer)])
+	parser.raw_buffer = parser.raw_buffer[:len(parser.raw_buffer)+size_read]
+	if err == io.EOF {
+		parser.eof = true
+	} else if err != nil {
+		return yaml_parser_set_reader_error(parser, "input error: "+err.Error(), parser.offset, -1)
+	}
+	return true
+}
+
+// Ensure that the buffer contains at least `length` characters.
+// Return true on success, false on failure.
+//
+// The length is supposed to be significantly less that the buffer size.
+func yaml_parser_update_buffer(parser *yaml_parser_t, length int) bool {
+	if parser.read_handler == nil {
+		panic("read handler must be set")
+	}
+
+	// [Go] This function was changed to guarantee the requested length size at EOF.
+	// The fact we need to do this is pretty awful, but the description above implies
+	// for that to be the case, and there are tests 
+
+	// If the EOF flag is set and the raw buffer is empty, do nothing.
+	if parser.eof && parser.raw_buffer_pos == len(parser.raw_buffer) {
+		// [Go] ACTUALLY! Read the documentation of this function above.
+		// This is just broken. To return true, we need to have the
+		// given length in the buffer. Not doing that means every single
+		// check that calls this function to make sure the buffer has a
+		// given length is Go) panicking; or C) accessing invalid memory.
+		//return true
+	}
+
+	// Return if the buffer contains enough characters.
+	if parser.unread >= length {
+		return true
+	}
+
+	// Determine the input encoding if it is not known yet.
+	if parser.encoding == yaml_ANY_ENCODING {
+		if !yaml_parser_determine_encoding(parser) {
+			return false
+		}
+	}
+
+	// Move the unread characters to the beginning of the buffer.
+	buffer_len := len(parser.buffer)
+	if parser.buffer_pos > 0 && parser.buffer_pos < buffer_len {
+		copy(parser.buffer, parser.buffer[parser.buffer_pos:])
+		buffer_len -= parser.buffer_pos
+		parser.buffer_pos = 0
+	} else if parser.buffer_pos == buffer_len {
+		buffer_len = 0
+		parser.buffer_pos = 0
+	}
+
+	// Open the whole buffer for writing, and cut it before returning.
+	parser.buffer = parser.buffer[:cap(parser.buffer)]
+
+	// Fill the buffer until it has enough characters.
+	first := true
+	for parser.unread < length {
+
+		// Fill the raw buffer if necessary.
+		if !first || parser.raw_buffer_pos == len(parser.raw_buffer) {
+			if !yaml_parser_update_raw_buffer(parser) {
+				parser.buffer = parser.buffer[:buffer_len]
+				return false
+			}
+		}
+		first = false
+
+		// Decode the raw buffer.
+	inner:
+		for parser.raw_buffer_pos != len(parser.raw_buffer) {
+			var value rune
+			var width int
+
+			raw_unread := len(parser.raw_buffer) - parser.raw_buffer_pos
+
+			// Decode the next character.
+			switch parser.encoding {
+			case yaml_UTF8_ENCODING:
+				// Decode a UTF-8 character.  Check RFC 3629
+				// (http://www.ietf.org/rfc/rfc3629.txt) for more details.
+				//
+				// The following table (taken from the RFC) is used for
+				// decoding.
+				//
+				//    Char. number range |        UTF-8 octet sequence
+				//      (hexadecimal)    |              (binary)
+				//   --------------------+------------------------------------
+				//   0000 0000-0000 007F | 0xxxxxxx
+				//   0000 0080-0000 07FF | 110xxxxx 10xxxxxx
+				//   0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
+				//   0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+				//
+				// Additionally, the characters in the range 0xD800-0xDFFF
+				// are prohibited as they are reserved for use with UTF-16
+				// surrogate pairs.
+
+				// Determine the length of the UTF-8 sequence.
+				octet := parser.raw_buffer[parser.raw_buffer_pos]
+				switch {
+				case octet&0x80 == 0x00:
+					width = 1
+				case octet&0xE0 == 0xC0:
+					width = 2
+				case octet&0xF0 == 0xE0:
+					width = 3
+				case octet&0xF8 == 0xF0:
+					width = 4
+				default:
+					// The leading octet is invalid.
+					return yaml_parser_set_reader_error(parser,
+						"invalid leading UTF-8 octet",
+						parser.offset, int(octet))
+				}
+
+				// Check if the raw buffer contains an incomplete character.
+				if width > raw_unread {
+					if parser.eof {
+						return yaml_parser_set_reader_error(parser,
+							"incomplete UTF-8 octet sequence",
+							parser.offset, -1)
+					}
+					break inner
+				}
+
+				// Decode the leading octet.
+				switch {
+				case octet&0x80 == 0x00:
+					value = rune(octet & 0x7F)
+				case octet&0xE0 == 0xC0:
+					value = rune(octet & 0x1F)
+				case octet&0xF0 == 0xE0:
+					value = rune(octet & 0x0F)
+				case octet&0xF8 == 0xF0:
+					value = rune(octet & 0x07)
+				default:
+					value = 0
+				}
+
+				// Check and decode the trailing octets.
+				for k := 1; k < width; k++ {
+					octet = parser.raw_buffer[parser.raw_buffer_pos+k]
+
+					// Check if the octet is valid.
+					if (octet & 0xC0) != 0x80 {
+						return yaml_parser_set_reader_error(parser,
+							"invalid trailing UTF-8 octet",
+							parser.offset+k, int(octet))
+					}
+
+					// Decode the octet.
+					value = (value << 6) + rune(octet&0x3F)
+				}
+
+				// Check the length of the sequence against the value.
+				switch {
+				case width == 1:
+				case width == 2 && value >= 0x80:
+				case width == 3 && value >= 0x800:
+				case width == 4 && value >= 0x10000:
+				default:
+					return yaml_parser_set_reader_error(parser,
+						"invalid length of a UTF-8 sequence",
+						parser.offset, -1)
+				}
+
+				// Check the range of the value.
+				if value >= 0xD800 && value <= 0xDFFF || value > 0x10FFFF {
+					return yaml_parser_set_reader_error(parser,
+						"invalid Unicode character",
+						parser.offset, int(value))
+				}
+
+			case yaml_UTF16LE_ENCODING, yaml_UTF16BE_ENCODING:
+				var low, high int
+				if parser.encoding == yaml_UTF16LE_ENCODING {
+					low, high = 0, 1
+				} else {
+					low, high = 1, 0
+				}
+
+				// The UTF-16 encoding is not as simple as one might
+				// naively think.  Check RFC 2781
+				// (http://www.ietf.org/rfc/rfc2781.txt).
+				//
+				// Normally, two subsequent bytes describe a Unicode
+				// character.  However a special technique (called a
+				// surrogate pair) is used for specifying character
+				// values larger than 0xFFFF.
+				//
+				// A surrogate pair consists of two pseudo-characters:
+				//      high surrogate area (0xD800-0xDBFF)
+				//      low surrogate area (0xDC00-0xDFFF)
+				//
+				// The following formulas are used for decoding
+				// and encoding characters using surrogate pairs:
+				//
+				//  U  = U' + 0x10000   (0x01 00 00 <= U <= 0x10 FF FF)
+				//  U' = yyyyyyyyyyxxxxxxxxxx   (0 <= U' <= 0x0F FF FF)
+				//  W1 = 110110yyyyyyyyyy
+				//  W2 = 110111xxxxxxxxxx
+				//
+				// where U is the character value, W1 is the high surrogate
+				// area, W2 is the low surrogate area.
+
+				// Check for incomplete UTF-16 character.
+				if raw_unread < 2 {
+					if parser.eof {
+						return yaml_parser_set_reader_error(parser,
+							"incomplete UTF-16 character",
+							parser.offset, -1)
+					}
+					break inner
+				}
+
+				// Get the character.
+				value = rune(parser.raw_buffer[parser.raw_buffer_pos+low]) +
+					(rune(parser.raw_buffer[parser.raw_buffer_pos+high]) << 8)
+
+				// Check for unexpected low surrogate area.
+				if value&0xFC00 == 0xDC00 {
+					return yaml_parser_set_reader_error(parser,
+						"unexpected low surrogate area",
+						parser.offset, int(value))
+				}
+
+				// Check for a high surrogate area.
+				if value&0xFC00 == 0xD800 {
+					width = 4
+
+					// Check for incomplete surrogate pair.
+					if raw_unread < 4 {
+						if parser.eof {
+							return yaml_parser_set_reader_error(parser,
+								"incomplete UTF-16 surrogate pair",
+								parser.offset, -1)
+						}
+						break inner
+					}
+
+					// Get the next character.
+					value2 := rune(parser.raw_buffer[parser.raw_buffer_pos+low+2]) +
+						(rune(parser.raw_buffer[parser.raw_buffer_pos+high+2]) << 8)
+
+					// Check for a low surrogate area.
+					if value2&0xFC00 != 0xDC00 {
+						return yaml_parser_set_reader_error(parser,
+							"expected low surrogate area",
+							parser.offset+2, int(value2))
+					}
+
+					// Generate the value of the surrogate pair.
+					value = 0x10000 + ((value & 0x3FF) << 10) + (value2 & 0x3FF)
+				} else {
+					width = 2
+				}
+
+			default:
+				panic("impossible")
+			}
+
+			// Check if the character is in the allowed range:
+			//      #x9 | #xA | #xD | [#x20-#x7E]               (8 bit)
+			//      | #x85 | [#xA0-#xD7FF] | [#xE000-#xFFFD]    (16 bit)
+			//      | [#x10000-#x10FFFF]                        (32 bit)
+			switch {
+			case value == 0x09:
+			case value == 0x0A:
+			case value == 0x0D:
+			case value >= 0x20 && value <= 0x7E:
+			case value == 0x85:
+			case value >= 0xA0 && value <= 0xD7FF:
+			case value >= 0xE000 && value <= 0xFFFD:
+			case value >= 0x10000 && value <= 0x10FFFF:
+			default:
+				return yaml_parser_set_reader_error(parser,
+					"control characters are not allowed",
+					parser.offset, int(value))
+			}
+
+			// Move the raw pointers.
+			parser.raw_buffer_pos += width
+			parser.offset += width
+
+			// Finally put the character into the buffer.
+			if value <= 0x7F {
+				// 0000 0000-0000 007F . 0xxxxxxx
+				parser.buffer[buffer_len+0] = byte(value)
+				buffer_len += 1
+			} else if value <= 0x7FF {
+				// 0000 0080-0000 07FF . 110xxxxx 10xxxxxx
+				parser.buffer[buffer_len+0] = byte(0xC0 + (value >> 6))
+				parser.buffer[buffer_len+1] = byte(0x80 + (value & 0x3F))
+				buffer_len += 2
+			} else if value <= 0xFFFF {
+				// 0000 0800-0000 FFFF . 1110xxxx 10xxxxxx 10xxxxxx
+				parser.buffer[buffer_len+0] = byte(0xE0 + (value >> 12))
+				parser.buffer[buffer_len+1] = byte(0x80 + ((value >> 6) & 0x3F))
+				parser.buffer[buffer_len+2] = byte(0x80 + (value & 0x3F))
+				buffer_len += 3
+			} else {
+				// 0001 0000-0010 FFFF . 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+				parser.buffer[buffer_len+0] = byte(0xF0 + (value >> 18))
+				parser.buffer[buffer_len+1] = byte(0x80 + ((value >> 12) & 0x3F))
+				parser.buffer[buffer_len+2] = byte(0x80 + ((value >> 6) & 0x3F))
+				parser.buffer[buffer_len+3] = byte(0x80 + (value & 0x3F))
+				buffer_len += 4
+			}
+
+			parser.unread++
+		}
+
+		// On EOF, put NUL into the buffer and return.
+		if parser.eof {
+			parser.buffer[buffer_len] = 0
+			buffer_len++
+			parser.unread++
+			break
+		}
+	}
+	// [Go] Read the documentation of this function above. To return true,
+	// we need to have the given length in the buffer. Not doing that means
+	// every single check that calls this function to make sure the buffer
+	// has a given length is Go) panicking; or C) accessing invalid memory.
+	// This happens here due to the EOF above breaking early.
+	for buffer_len < length {
+		parser.buffer[buffer_len] = 0
+		buffer_len++
+	}
+	parser.buffer = parser.buffer[:buffer_len]
+	return true
+}

+ 258 - 0
vendor/gopkg.in/yaml.v2/resolve.go

@@ -0,0 +1,258 @@
+package yaml
+
+import (
+	"encoding/base64"
+	"math"
+	"regexp"
+	"strconv"
+	"strings"
+	"time"
+)
+
+type resolveMapItem struct {
+	value interface{}
+	tag   string
+}
+
+var resolveTable = make([]byte, 256)
+var resolveMap = make(map[string]resolveMapItem)
+
+func init() {
+	t := resolveTable
+	t[int('+')] = 'S' // Sign
+	t[int('-')] = 'S'
+	for _, c := range "0123456789" {
+		t[int(c)] = 'D' // Digit
+	}
+	for _, c := range "yYnNtTfFoO~" {
+		t[int(c)] = 'M' // In map
+	}
+	t[int('.')] = '.' // Float (potentially in map)
+
+	var resolveMapList = []struct {
+		v   interface{}
+		tag string
+		l   []string
+	}{
+		{true, yaml_BOOL_TAG, []string{"y", "Y", "yes", "Yes", "YES"}},
+		{true, yaml_BOOL_TAG, []string{"true", "True", "TRUE"}},
+		{true, yaml_BOOL_TAG, []string{"on", "On", "ON"}},
+		{false, yaml_BOOL_TAG, []string{"n", "N", "no", "No", "NO"}},
+		{false, yaml_BOOL_TAG, []string{"false", "False", "FALSE"}},
+		{false, yaml_BOOL_TAG, []string{"off", "Off", "OFF"}},
+		{nil, yaml_NULL_TAG, []string{"", "~", "null", "Null", "NULL"}},
+		{math.NaN(), yaml_FLOAT_TAG, []string{".nan", ".NaN", ".NAN"}},
+		{math.Inf(+1), yaml_FLOAT_TAG, []string{".inf", ".Inf", ".INF"}},
+		{math.Inf(+1), yaml_FLOAT_TAG, []string{"+.inf", "+.Inf", "+.INF"}},
+		{math.Inf(-1), yaml_FLOAT_TAG, []string{"-.inf", "-.Inf", "-.INF"}},
+		{"<<", yaml_MERGE_TAG, []string{"<<"}},
+	}
+
+	m := resolveMap
+	for _, item := range resolveMapList {
+		for _, s := range item.l {
+			m[s] = resolveMapItem{item.v, item.tag}
+		}
+	}
+}
+
+const longTagPrefix = "tag:yaml.org,2002:"
+
+func shortTag(tag string) string {
+	// TODO This can easily be made faster and produce less garbage.
+	if strings.HasPrefix(tag, longTagPrefix) {
+		return "!!" + tag[len(longTagPrefix):]
+	}
+	return tag
+}
+
+func longTag(tag string) string {
+	if strings.HasPrefix(tag, "!!") {
+		return longTagPrefix + tag[2:]
+	}
+	return tag
+}
+
+func resolvableTag(tag string) bool {
+	switch tag {
+	case "", yaml_STR_TAG, yaml_BOOL_TAG, yaml_INT_TAG, yaml_FLOAT_TAG, yaml_NULL_TAG, yaml_TIMESTAMP_TAG:
+		return true
+	}
+	return false
+}
+
+var yamlStyleFloat = regexp.MustCompile(`^[-+]?[0-9]*\.?[0-9]+([eE][-+][0-9]+)?$`)
+
+func resolve(tag string, in string) (rtag string, out interface{}) {
+	if !resolvableTag(tag) {
+		return tag, in
+	}
+
+	defer func() {
+		switch tag {
+		case "", rtag, yaml_STR_TAG, yaml_BINARY_TAG:
+			return
+		case yaml_FLOAT_TAG:
+			if rtag == yaml_INT_TAG {
+				switch v := out.(type) {
+				case int64:
+					rtag = yaml_FLOAT_TAG
+					out = float64(v)
+					return
+				case int:
+					rtag = yaml_FLOAT_TAG
+					out = float64(v)
+					return
+				}
+			}
+		}
+		failf("cannot decode %s `%s` as a %s", shortTag(rtag), in, shortTag(tag))
+	}()
+
+	// Any data is accepted as a !!str or !!binary.
+	// Otherwise, the prefix is enough of a hint about what it might be.
+	hint := byte('N')
+	if in != "" {
+		hint = resolveTable[in[0]]
+	}
+	if hint != 0 && tag != yaml_STR_TAG && tag != yaml_BINARY_TAG {
+		// Handle things we can lookup in a map.
+		if item, ok := resolveMap[in]; ok {
+			return item.tag, item.value
+		}
+
+		// Base 60 floats are a bad idea, were dropped in YAML 1.2, and
+		// are purposefully unsupported here. They're still quoted on
+		// the way out for compatibility with other parser, though.
+
+		switch hint {
+		case 'M':
+			// We've already checked the map above.
+
+		case '.':
+			// Not in the map, so maybe a normal float.
+			floatv, err := strconv.ParseFloat(in, 64)
+			if err == nil {
+				return yaml_FLOAT_TAG, floatv
+			}
+
+		case 'D', 'S':
+			// Int, float, or timestamp.
+			// Only try values as a timestamp if the value is unquoted or there's an explicit
+			// !!timestamp tag.
+			if tag == "" || tag == yaml_TIMESTAMP_TAG {
+				t, ok := parseTimestamp(in)
+				if ok {
+					return yaml_TIMESTAMP_TAG, t
+				}
+			}
+
+			plain := strings.Replace(in, "_", "", -1)
+			intv, err := strconv.ParseInt(plain, 0, 64)
+			if err == nil {
+				if intv == int64(int(intv)) {
+					return yaml_INT_TAG, int(intv)
+				} else {
+					return yaml_INT_TAG, intv
+				}
+			}
+			uintv, err := strconv.ParseUint(plain, 0, 64)
+			if err == nil {
+				return yaml_INT_TAG, uintv
+			}
+			if yamlStyleFloat.MatchString(plain) {
+				floatv, err := strconv.ParseFloat(plain, 64)
+				if err == nil {
+					return yaml_FLOAT_TAG, floatv
+				}
+			}
+			if strings.HasPrefix(plain, "0b") {
+				intv, err := strconv.ParseInt(plain[2:], 2, 64)
+				if err == nil {
+					if intv == int64(int(intv)) {
+						return yaml_INT_TAG, int(intv)
+					} else {
+						return yaml_INT_TAG, intv
+					}
+				}
+				uintv, err := strconv.ParseUint(plain[2:], 2, 64)
+				if err == nil {
+					return yaml_INT_TAG, uintv
+				}
+			} else if strings.HasPrefix(plain, "-0b") {
+				intv, err := strconv.ParseInt("-" + plain[3:], 2, 64)
+				if err == nil {
+					if true || intv == int64(int(intv)) {
+						return yaml_INT_TAG, int(intv)
+					} else {
+						return yaml_INT_TAG, intv
+					}
+				}
+			}
+		default:
+			panic("resolveTable item not yet handled: " + string(rune(hint)) + " (with " + in + ")")
+		}
+	}
+	return yaml_STR_TAG, in
+}
+
+// encodeBase64 encodes s as base64 that is broken up into multiple lines
+// as appropriate for the resulting length.
+func encodeBase64(s string) string {
+	const lineLen = 70
+	encLen := base64.StdEncoding.EncodedLen(len(s))
+	lines := encLen/lineLen + 1
+	buf := make([]byte, encLen*2+lines)
+	in := buf[0:encLen]
+	out := buf[encLen:]
+	base64.StdEncoding.Encode(in, []byte(s))
+	k := 0
+	for i := 0; i < len(in); i += lineLen {
+		j := i + lineLen
+		if j > len(in) {
+			j = len(in)
+		}
+		k += copy(out[k:], in[i:j])
+		if lines > 1 {
+			out[k] = '\n'
+			k++
+		}
+	}
+	return string(out[:k])
+}
+
+// This is a subset of the formats allowed by the regular expression
+// defined at http://yaml.org/type/timestamp.html.
+var allowedTimestampFormats = []string{
+	"2006-1-2T15:4:5.999999999Z07:00", // RCF3339Nano with short date fields.
+	"2006-1-2t15:4:5.999999999Z07:00", // RFC3339Nano with short date fields and lower-case "t".
+	"2006-1-2 15:4:5.999999999",       // space separated with no time zone
+	"2006-1-2",                        // date only
+	// Notable exception: time.Parse cannot handle: "2001-12-14 21:59:43.10 -5"
+	// from the set of examples.
+}
+
+// parseTimestamp parses s as a timestamp string and
+// returns the timestamp and reports whether it succeeded.
+// Timestamp formats are defined at http://yaml.org/type/timestamp.html
+func parseTimestamp(s string) (time.Time, bool) {
+	// TODO write code to check all the formats supported by
+	// http://yaml.org/type/timestamp.html instead of using time.Parse.
+
+	// Quick check: all date formats start with YYYY-.
+	i := 0
+	for ; i < len(s); i++ {
+		if c := s[i]; c < '0' || c > '9' {
+			break
+		}
+	}
+	if i != 4 || i == len(s) || s[i] != '-' {
+		return time.Time{}, false
+	}
+	for _, format := range allowedTimestampFormats {
+		if t, err := time.Parse(format, s); err == nil {
+			return t, true
+		}
+	}
+	return time.Time{}, false
+}

+ 2696 - 0
vendor/gopkg.in/yaml.v2/scannerc.go

@@ -0,0 +1,2696 @@
+package yaml
+
+import (
+	"bytes"
+	"fmt"
+)
+
+// Introduction
+// ************
+//
+// The following notes assume that you are familiar with the YAML specification
+// (http://yaml.org/spec/1.2/spec.html).  We mostly follow it, although in
+// some cases we are less restrictive that it requires.
+//
+// The process of transforming a YAML stream into a sequence of events is
+// divided on two steps: Scanning and Parsing.
+//
+// The Scanner transforms the input stream into a sequence of tokens, while the
+// parser transform the sequence of tokens produced by the Scanner into a
+// sequence of parsing events.
+//
+// The Scanner is rather clever and complicated. The Parser, on the contrary,
+// is a straightforward implementation of a recursive-descendant parser (or,
+// LL(1) parser, as it is usually called).
+//
+// Actually there are two issues of Scanning that might be called "clever", the
+// rest is quite straightforward.  The issues are "block collection start" and
+// "simple keys".  Both issues are explained below in details.
+//
+// Here the Scanning step is explained and implemented.  We start with the list
+// of all the tokens produced by the Scanner together with short descriptions.
+//
+// Now, tokens:
+//
+//      STREAM-START(encoding)          # The stream start.
+//      STREAM-END                      # The stream end.
+//      VERSION-DIRECTIVE(major,minor)  # The '%YAML' directive.
+//      TAG-DIRECTIVE(handle,prefix)    # The '%TAG' directive.
+//      DOCUMENT-START                  # '---'
+//      DOCUMENT-END                    # '...'
+//      BLOCK-SEQUENCE-START            # Indentation increase denoting a block
+//      BLOCK-MAPPING-START             # sequence or a block mapping.
+//      BLOCK-END                       # Indentation decrease.
+//      FLOW-SEQUENCE-START             # '['
+//      FLOW-SEQUENCE-END               # ']'
+//      BLOCK-SEQUENCE-START            # '{'
+//      BLOCK-SEQUENCE-END              # '}'
+//      BLOCK-ENTRY                     # '-'
+//      FLOW-ENTRY                      # ','
+//      KEY                             # '?' or nothing (simple keys).
+//      VALUE                           # ':'
+//      ALIAS(anchor)                   # '*anchor'
+//      ANCHOR(anchor)                  # '&anchor'
+//      TAG(handle,suffix)              # '!handle!suffix'
+//      SCALAR(value,style)             # A scalar.
+//
+// The following two tokens are "virtual" tokens denoting the beginning and the
+// end of the stream:
+//
+//      STREAM-START(encoding)
+//      STREAM-END
+//
+// We pass the information about the input stream encoding with the
+// STREAM-START token.
+//
+// The next two tokens are responsible for tags:
+//
+//      VERSION-DIRECTIVE(major,minor)
+//      TAG-DIRECTIVE(handle,prefix)
+//
+// Example:
+//
+//      %YAML   1.1
+//      %TAG    !   !foo
+//      %TAG    !yaml!  tag:yaml.org,2002:
+//      ---
+//
+// The correspoding sequence of tokens:
+//
+//      STREAM-START(utf-8)
+//      VERSION-DIRECTIVE(1,1)
+//      TAG-DIRECTIVE("!","!foo")
+//      TAG-DIRECTIVE("!yaml","tag:yaml.org,2002:")
+//      DOCUMENT-START
+//      STREAM-END
+//
+// Note that the VERSION-DIRECTIVE and TAG-DIRECTIVE tokens occupy a whole
+// line.
+//
+// The document start and end indicators are represented by:
+//
+//      DOCUMENT-START
+//      DOCUMENT-END
+//
+// Note that if a YAML stream contains an implicit document (without '---'
+// and '...' indicators), no DOCUMENT-START and DOCUMENT-END tokens will be
+// produced.
+//
+// In the following examples, we present whole documents together with the
+// produced tokens.
+//
+//      1. An implicit document:
+//
+//          'a scalar'
+//
+//      Tokens:
+//
+//          STREAM-START(utf-8)
+//          SCALAR("a scalar",single-quoted)
+//          STREAM-END
+//
+//      2. An explicit document:
+//
+//          ---
+//          'a scalar'
+//          ...
+//
+//      Tokens:
+//
+//          STREAM-START(utf-8)
+//          DOCUMENT-START
+//          SCALAR("a scalar",single-quoted)
+//          DOCUMENT-END
+//          STREAM-END
+//
+//      3. Several documents in a stream:
+//
+//          'a scalar'
+//          ---
+//          'another scalar'
+//          ---
+//          'yet another scalar'
+//
+//      Tokens:
+//
+//          STREAM-START(utf-8)
+//          SCALAR("a scalar",single-quoted)
+//          DOCUMENT-START
+//          SCALAR("another scalar",single-quoted)
+//          DOCUMENT-START
+//          SCALAR("yet another scalar",single-quoted)
+//          STREAM-END
+//
+// We have already introduced the SCALAR token above.  The following tokens are
+// used to describe aliases, anchors, tag, and scalars:
+//
+//      ALIAS(anchor)
+//      ANCHOR(anchor)
+//      TAG(handle,suffix)
+//      SCALAR(value,style)
+//
+// The following series of examples illustrate the usage of these tokens:
+//
+//      1. A recursive sequence:
+//
+//          &A [ *A ]
+//
+//      Tokens:
+//
+//          STREAM-START(utf-8)
+//          ANCHOR("A")
+//          FLOW-SEQUENCE-START
+//          ALIAS("A")
+//          FLOW-SEQUENCE-END
+//          STREAM-END
+//
+//      2. A tagged scalar:
+//
+//          !!float "3.14"  # A good approximation.
+//
+//      Tokens:
+//
+//          STREAM-START(utf-8)
+//          TAG("!!","float")
+//          SCALAR("3.14",double-quoted)
+//          STREAM-END
+//
+//      3. Various scalar styles:
+//
+//          --- # Implicit empty plain scalars do not produce tokens.
+//          --- a plain scalar
+//          --- 'a single-quoted scalar'
+//          --- "a double-quoted scalar"
+//          --- |-
+//            a literal scalar
+//          --- >-
+//            a folded
+//            scalar
+//
+//      Tokens:
+//
+//          STREAM-START(utf-8)
+//          DOCUMENT-START
+//          DOCUMENT-START
+//          SCALAR("a plain scalar",plain)
+//          DOCUMENT-START
+//          SCALAR("a single-quoted scalar",single-quoted)
+//          DOCUMENT-START
+//          SCALAR("a double-quoted scalar",double-quoted)
+//          DOCUMENT-START
+//          SCALAR("a literal scalar",literal)
+//          DOCUMENT-START
+//          SCALAR("a folded scalar",folded)
+//          STREAM-END
+//
+// Now it's time to review collection-related tokens. We will start with
+// flow collections:
+//
+//      FLOW-SEQUENCE-START
+//      FLOW-SEQUENCE-END
+//      FLOW-MAPPING-START
+//      FLOW-MAPPING-END
+//      FLOW-ENTRY
+//      KEY
+//      VALUE
+//
+// The tokens FLOW-SEQUENCE-START, FLOW-SEQUENCE-END, FLOW-MAPPING-START, and
+// FLOW-MAPPING-END represent the indicators '[', ']', '{', and '}'
+// correspondingly.  FLOW-ENTRY represent the ',' indicator.  Finally the
+// indicators '?' and ':', which are used for denoting mapping keys and values,
+// are represented by the KEY and VALUE tokens.
+//
+// The following examples show flow collections:
+//
+//      1. A flow sequence:
+//
+//          [item 1, item 2, item 3]
+//
+//      Tokens:
+//
+//          STREAM-START(utf-8)
+//          FLOW-SEQUENCE-START
+//          SCALAR("item 1",plain)
+//          FLOW-ENTRY
+//          SCALAR("item 2",plain)
+//          FLOW-ENTRY
+//          SCALAR("item 3",plain)
+//          FLOW-SEQUENCE-END
+//          STREAM-END
+//
+//      2. A flow mapping:
+//
+//          {
+//              a simple key: a value,  # Note that the KEY token is produced.
+//              ? a complex key: another value,
+//          }
+//
+//      Tokens:
+//
+//          STREAM-START(utf-8)
+//          FLOW-MAPPING-START
+//          KEY
+//          SCALAR("a simple key",plain)
+//          VALUE
+//          SCALAR("a value",plain)
+//          FLOW-ENTRY
+//          KEY
+//          SCALAR("a complex key",plain)
+//          VALUE
+//          SCALAR("another value",plain)
+//          FLOW-ENTRY
+//          FLOW-MAPPING-END
+//          STREAM-END
+//
+// A simple key is a key which is not denoted by the '?' indicator.  Note that
+// the Scanner still produce the KEY token whenever it encounters a simple key.
+//
+// For scanning block collections, the following tokens are used (note that we
+// repeat KEY and VALUE here):
+//
+//      BLOCK-SEQUENCE-START
+//      BLOCK-MAPPING-START
+//      BLOCK-END
+//      BLOCK-ENTRY
+//      KEY
+//      VALUE
+//
+// The tokens BLOCK-SEQUENCE-START and BLOCK-MAPPING-START denote indentation
+// increase that precedes a block collection (cf. the INDENT token in Python).
+// The token BLOCK-END denote indentation decrease that ends a block collection
+// (cf. the DEDENT token in Python).  However YAML has some syntax pecularities
+// that makes detections of these tokens more complex.
+//
+// The tokens BLOCK-ENTRY, KEY, and VALUE are used to represent the indicators
+// '-', '?', and ':' correspondingly.
+//
+// The following examples show how the tokens BLOCK-SEQUENCE-START,
+// BLOCK-MAPPING-START, and BLOCK-END are emitted by the Scanner:
+//
+//      1. Block sequences:
+//
+//          - item 1
+//          - item 2
+//          -
+//            - item 3.1
+//            - item 3.2
+//          -
+//            key 1: value 1
+//            key 2: value 2
+//
+//      Tokens:
+//
+//          STREAM-START(utf-8)
+//          BLOCK-SEQUENCE-START
+//          BLOCK-ENTRY
+//          SCALAR("item 1",plain)
+//          BLOCK-ENTRY
+//          SCALAR("item 2",plain)
+//          BLOCK-ENTRY
+//          BLOCK-SEQUENCE-START
+//          BLOCK-ENTRY
+//          SCALAR("item 3.1",plain)
+//          BLOCK-ENTRY
+//          SCALAR("item 3.2",plain)
+//          BLOCK-END
+//          BLOCK-ENTRY
+//          BLOCK-MAPPING-START
+//          KEY
+//          SCALAR("key 1",plain)
+//          VALUE
+//          SCALAR("value 1",plain)
+//          KEY
+//          SCALAR("key 2",plain)
+//          VALUE
+//          SCALAR("value 2",plain)
+//          BLOCK-END
+//          BLOCK-END
+//          STREAM-END
+//
+//      2. Block mappings:
+//
+//          a simple key: a value   # The KEY token is produced here.
+//          ? a complex key
+//          : another value
+//          a mapping:
+//            key 1: value 1
+//            key 2: value 2
+//          a sequence:
+//            - item 1
+//            - item 2
+//
+//      Tokens:
+//
+//          STREAM-START(utf-8)
+//          BLOCK-MAPPING-START
+//          KEY
+//          SCALAR("a simple key",plain)
+//          VALUE
+//          SCALAR("a value",plain)
+//          KEY
+//          SCALAR("a complex key",plain)
+//          VALUE
+//          SCALAR("another value",plain)
+//          KEY
+//          SCALAR("a mapping",plain)
+//          BLOCK-MAPPING-START
+//          KEY
+//          SCALAR("key 1",plain)
+//          VALUE
+//          SCALAR("value 1",plain)
+//          KEY
+//          SCALAR("key 2",plain)
+//          VALUE
+//          SCALAR("value 2",plain)
+//          BLOCK-END
+//          KEY
+//          SCALAR("a sequence",plain)
+//          VALUE
+//          BLOCK-SEQUENCE-START
+//          BLOCK-ENTRY
+//          SCALAR("item 1",plain)
+//          BLOCK-ENTRY
+//          SCALAR("item 2",plain)
+//          BLOCK-END
+//          BLOCK-END
+//          STREAM-END
+//
+// YAML does not always require to start a new block collection from a new
+// line.  If the current line contains only '-', '?', and ':' indicators, a new
+// block collection may start at the current line.  The following examples
+// illustrate this case:
+//
+//      1. Collections in a sequence:
+//
+//          - - item 1
+//            - item 2
+//          - key 1: value 1
+//            key 2: value 2
+//          - ? complex key
+//            : complex value
+//
+//      Tokens:
+//
+//          STREAM-START(utf-8)
+//          BLOCK-SEQUENCE-START
+//          BLOCK-ENTRY
+//          BLOCK-SEQUENCE-START
+//          BLOCK-ENTRY
+//          SCALAR("item 1",plain)
+//          BLOCK-ENTRY
+//          SCALAR("item 2",plain)
+//          BLOCK-END
+//          BLOCK-ENTRY
+//          BLOCK-MAPPING-START
+//          KEY
+//          SCALAR("key 1",plain)
+//          VALUE
+//          SCALAR("value 1",plain)
+//          KEY
+//          SCALAR("key 2",plain)
+//          VALUE
+//          SCALAR("value 2",plain)
+//          BLOCK-END
+//          BLOCK-ENTRY
+//          BLOCK-MAPPING-START
+//          KEY
+//          SCALAR("complex key")
+//          VALUE
+//          SCALAR("complex value")
+//          BLOCK-END
+//          BLOCK-END
+//          STREAM-END
+//
+//      2. Collections in a mapping:
+//
+//          ? a sequence
+//          : - item 1
+//            - item 2
+//          ? a mapping
+//          : key 1: value 1
+//            key 2: value 2
+//
+//      Tokens:
+//
+//          STREAM-START(utf-8)
+//          BLOCK-MAPPING-START
+//          KEY
+//          SCALAR("a sequence",plain)
+//          VALUE
+//          BLOCK-SEQUENCE-START
+//          BLOCK-ENTRY
+//          SCALAR("item 1",plain)
+//          BLOCK-ENTRY
+//          SCALAR("item 2",plain)
+//          BLOCK-END
+//          KEY
+//          SCALAR("a mapping",plain)
+//          VALUE
+//          BLOCK-MAPPING-START
+//          KEY
+//          SCALAR("key 1",plain)
+//          VALUE
+//          SCALAR("value 1",plain)
+//          KEY
+//          SCALAR("key 2",plain)
+//          VALUE
+//          SCALAR("value 2",plain)
+//          BLOCK-END
+//          BLOCK-END
+//          STREAM-END
+//
+// YAML also permits non-indented sequences if they are included into a block
+// mapping.  In this case, the token BLOCK-SEQUENCE-START is not produced:
+//
+//      key:
+//      - item 1    # BLOCK-SEQUENCE-START is NOT produced here.
+//      - item 2
+//
+// Tokens:
+//
+//      STREAM-START(utf-8)
+//      BLOCK-MAPPING-START
+//      KEY
+//      SCALAR("key",plain)
+//      VALUE
+//      BLOCK-ENTRY
+//      SCALAR("item 1",plain)
+//      BLOCK-ENTRY
+//      SCALAR("item 2",plain)
+//      BLOCK-END
+//
+
+// Ensure that the buffer contains the required number of characters.
+// Return true on success, false on failure (reader error or memory error).
+func cache(parser *yaml_parser_t, length int) bool {
+	// [Go] This was inlined: !cache(A, B) -> unread < B && !update(A, B)
+	return parser.unread >= length || yaml_parser_update_buffer(parser, length)
+}
+
+// Advance the buffer pointer.
+func skip(parser *yaml_parser_t) {
+	parser.mark.index++
+	parser.mark.column++
+	parser.unread--
+	parser.buffer_pos += width(parser.buffer[parser.buffer_pos])
+}
+
+func skip_line(parser *yaml_parser_t) {
+	if is_crlf(parser.buffer, parser.buffer_pos) {
+		parser.mark.index += 2
+		parser.mark.column = 0
+		parser.mark.line++
+		parser.unread -= 2
+		parser.buffer_pos += 2
+	} else if is_break(parser.buffer, parser.buffer_pos) {
+		parser.mark.index++
+		parser.mark.column = 0
+		parser.mark.line++
+		parser.unread--
+		parser.buffer_pos += width(parser.buffer[parser.buffer_pos])
+	}
+}
+
+// Copy a character to a string buffer and advance pointers.
+func read(parser *yaml_parser_t, s []byte) []byte {
+	w := width(parser.buffer[parser.buffer_pos])
+	if w == 0 {
+		panic("invalid character sequence")
+	}
+	if len(s) == 0 {
+		s = make([]byte, 0, 32)
+	}
+	if w == 1 && len(s)+w <= cap(s) {
+		s = s[:len(s)+1]
+		s[len(s)-1] = parser.buffer[parser.buffer_pos]
+		parser.buffer_pos++
+	} else {
+		s = append(s, parser.buffer[parser.buffer_pos:parser.buffer_pos+w]...)
+		parser.buffer_pos += w
+	}
+	parser.mark.index++
+	parser.mark.column++
+	parser.unread--
+	return s
+}
+
+// Copy a line break character to a string buffer and advance pointers.
+func read_line(parser *yaml_parser_t, s []byte) []byte {
+	buf := parser.buffer
+	pos := parser.buffer_pos
+	switch {
+	case buf[pos] == '\r' && buf[pos+1] == '\n':
+		// CR LF . LF
+		s = append(s, '\n')
+		parser.buffer_pos += 2
+		parser.mark.index++
+		parser.unread--
+	case buf[pos] == '\r' || buf[pos] == '\n':
+		// CR|LF . LF
+		s = append(s, '\n')
+		parser.buffer_pos += 1
+	case buf[pos] == '\xC2' && buf[pos+1] == '\x85':
+		// NEL . LF
+		s = append(s, '\n')
+		parser.buffer_pos += 2
+	case buf[pos] == '\xE2' && buf[pos+1] == '\x80' && (buf[pos+2] == '\xA8' || buf[pos+2] == '\xA9'):
+		// LS|PS . LS|PS
+		s = append(s, buf[parser.buffer_pos:pos+3]...)
+		parser.buffer_pos += 3
+	default:
+		return s
+	}
+	parser.mark.index++
+	parser.mark.column = 0
+	parser.mark.line++
+	parser.unread--
+	return s
+}
+
+// Get the next token.
+func yaml_parser_scan(parser *yaml_parser_t, token *yaml_token_t) bool {
+	// Erase the token object.
+	*token = yaml_token_t{} // [Go] Is this necessary?
+
+	// No tokens after STREAM-END or error.
+	if parser.stream_end_produced || parser.error != yaml_NO_ERROR {
+		return true
+	}
+
+	// Ensure that the tokens queue contains enough tokens.
+	if !parser.token_available {
+		if !yaml_parser_fetch_more_tokens(parser) {
+			return false
+		}
+	}
+
+	// Fetch the next token from the queue.
+	*token = parser.tokens[parser.tokens_head]
+	parser.tokens_head++
+	parser.tokens_parsed++
+	parser.token_available = false
+
+	if token.typ == yaml_STREAM_END_TOKEN {
+		parser.stream_end_produced = true
+	}
+	return true
+}
+
+// Set the scanner error and return false.
+func yaml_parser_set_scanner_error(parser *yaml_parser_t, context string, context_mark yaml_mark_t, problem string) bool {
+	parser.error = yaml_SCANNER_ERROR
+	parser.context = context
+	parser.context_mark = context_mark
+	parser.problem = problem
+	parser.problem_mark = parser.mark
+	return false
+}
+
+func yaml_parser_set_scanner_tag_error(parser *yaml_parser_t, directive bool, context_mark yaml_mark_t, problem string) bool {
+	context := "while parsing a tag"
+	if directive {
+		context = "while parsing a %TAG directive"
+	}
+	return yaml_parser_set_scanner_error(parser, context, context_mark, problem)
+}
+
+func trace(args ...interface{}) func() {
+	pargs := append([]interface{}{"+++"}, args...)
+	fmt.Println(pargs...)
+	pargs = append([]interface{}{"---"}, args...)
+	return func() { fmt.Println(pargs...) }
+}
+
+// Ensure that the tokens queue contains at least one token which can be
+// returned to the Parser.
+func yaml_parser_fetch_more_tokens(parser *yaml_parser_t) bool {
+	// While we need more tokens to fetch, do it.
+	for {
+		// Check if we really need to fetch more tokens.
+		need_more_tokens := false
+
+		if parser.tokens_head == len(parser.tokens) {
+			// Queue is empty.
+			need_more_tokens = true
+		} else {
+			// Check if any potential simple key may occupy the head position.
+			if !yaml_parser_stale_simple_keys(parser) {
+				return false
+			}
+
+			for i := range parser.simple_keys {
+				simple_key := &parser.simple_keys[i]
+				if simple_key.possible && simple_key.token_number == parser.tokens_parsed {
+					need_more_tokens = true
+					break
+				}
+			}
+		}
+
+		// We are finished.
+		if !need_more_tokens {
+			break
+		}
+		// Fetch the next token.
+		if !yaml_parser_fetch_next_token(parser) {
+			return false
+		}
+	}
+
+	parser.token_available = true
+	return true
+}
+
+// The dispatcher for token fetchers.
+func yaml_parser_fetch_next_token(parser *yaml_parser_t) bool {
+	// Ensure that the buffer is initialized.
+	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+		return false
+	}
+
+	// Check if we just started scanning.  Fetch STREAM-START then.
+	if !parser.stream_start_produced {
+		return yaml_parser_fetch_stream_start(parser)
+	}
+
+	// Eat whitespaces and comments until we reach the next token.
+	if !yaml_parser_scan_to_next_token(parser) {
+		return false
+	}
+
+	// Remove obsolete potential simple keys.
+	if !yaml_parser_stale_simple_keys(parser) {
+		return false
+	}
+
+	// Check the indentation level against the current column.
+	if !yaml_parser_unroll_indent(parser, parser.mark.column) {
+		return false
+	}
+
+	// Ensure that the buffer contains at least 4 characters.  4 is the length
+	// of the longest indicators ('--- ' and '... ').
+	if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) {
+		return false
+	}
+
+	// Is it the end of the stream?
+	if is_z(parser.buffer, parser.buffer_pos) {
+		return yaml_parser_fetch_stream_end(parser)
+	}
+
+	// Is it a directive?
+	if parser.mark.column == 0 && parser.buffer[parser.buffer_pos] == '%' {
+		return yaml_parser_fetch_directive(parser)
+	}
+
+	buf := parser.buffer
+	pos := parser.buffer_pos
+
+	// Is it the document start indicator?
+	if parser.mark.column == 0 && buf[pos] == '-' && buf[pos+1] == '-' && buf[pos+2] == '-' && is_blankz(buf, pos+3) {
+		return yaml_parser_fetch_document_indicator(parser, yaml_DOCUMENT_START_TOKEN)
+	}
+
+	// Is it the document end indicator?
+	if parser.mark.column == 0 && buf[pos] == '.' && buf[pos+1] == '.' && buf[pos+2] == '.' && is_blankz(buf, pos+3) {
+		return yaml_parser_fetch_document_indicator(parser, yaml_DOCUMENT_END_TOKEN)
+	}
+
+	// Is it the flow sequence start indicator?
+	if buf[pos] == '[' {
+		return yaml_parser_fetch_flow_collection_start(parser, yaml_FLOW_SEQUENCE_START_TOKEN)
+	}
+
+	// Is it the flow mapping start indicator?
+	if parser.buffer[parser.buffer_pos] == '{' {
+		return yaml_parser_fetch_flow_collection_start(parser, yaml_FLOW_MAPPING_START_TOKEN)
+	}
+
+	// Is it the flow sequence end indicator?
+	if parser.buffer[parser.buffer_pos] == ']' {
+		return yaml_parser_fetch_flow_collection_end(parser,
+			yaml_FLOW_SEQUENCE_END_TOKEN)
+	}
+
+	// Is it the flow mapping end indicator?
+	if parser.buffer[parser.buffer_pos] == '}' {
+		return yaml_parser_fetch_flow_collection_end(parser,
+			yaml_FLOW_MAPPING_END_TOKEN)
+	}
+
+	// Is it the flow entry indicator?
+	if parser.buffer[parser.buffer_pos] == ',' {
+		return yaml_parser_fetch_flow_entry(parser)
+	}
+
+	// Is it the block entry indicator?
+	if parser.buffer[parser.buffer_pos] == '-' && is_blankz(parser.buffer, parser.buffer_pos+1) {
+		return yaml_parser_fetch_block_entry(parser)
+	}
+
+	// Is it the key indicator?
+	if parser.buffer[parser.buffer_pos] == '?' && (parser.flow_level > 0 || is_blankz(parser.buffer, parser.buffer_pos+1)) {
+		return yaml_parser_fetch_key(parser)
+	}
+
+	// Is it the value indicator?
+	if parser.buffer[parser.buffer_pos] == ':' && (parser.flow_level > 0 || is_blankz(parser.buffer, parser.buffer_pos+1)) {
+		return yaml_parser_fetch_value(parser)
+	}
+
+	// Is it an alias?
+	if parser.buffer[parser.buffer_pos] == '*' {
+		return yaml_parser_fetch_anchor(parser, yaml_ALIAS_TOKEN)
+	}
+
+	// Is it an anchor?
+	if parser.buffer[parser.buffer_pos] == '&' {
+		return yaml_parser_fetch_anchor(parser, yaml_ANCHOR_TOKEN)
+	}
+
+	// Is it a tag?
+	if parser.buffer[parser.buffer_pos] == '!' {
+		return yaml_parser_fetch_tag(parser)
+	}
+
+	// Is it a literal scalar?
+	if parser.buffer[parser.buffer_pos] == '|' && parser.flow_level == 0 {
+		return yaml_parser_fetch_block_scalar(parser, true)
+	}
+
+	// Is it a folded scalar?
+	if parser.buffer[parser.buffer_pos] == '>' && parser.flow_level == 0 {
+		return yaml_parser_fetch_block_scalar(parser, false)
+	}
+
+	// Is it a single-quoted scalar?
+	if parser.buffer[parser.buffer_pos] == '\'' {
+		return yaml_parser_fetch_flow_scalar(parser, true)
+	}
+
+	// Is it a double-quoted scalar?
+	if parser.buffer[parser.buffer_pos] == '"' {
+		return yaml_parser_fetch_flow_scalar(parser, false)
+	}
+
+	// Is it a plain scalar?
+	//
+	// A plain scalar may start with any non-blank characters except
+	//
+	//      '-', '?', ':', ',', '[', ']', '{', '}',
+	//      '#', '&', '*', '!', '|', '>', '\'', '\"',
+	//      '%', '@', '`'.
+	//
+	// In the block context (and, for the '-' indicator, in the flow context
+	// too), it may also start with the characters
+	//
+	//      '-', '?', ':'
+	//
+	// if it is followed by a non-space character.
+	//
+	// The last rule is more restrictive than the specification requires.
+	// [Go] Make this logic more reasonable.
+	//switch parser.buffer[parser.buffer_pos] {
+	//case '-', '?', ':', ',', '?', '-', ',', ':', ']', '[', '}', '{', '&', '#', '!', '*', '>', '|', '"', '\'', '@', '%', '-', '`':
+	//}
+	if !(is_blankz(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == '-' ||
+		parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == ':' ||
+		parser.buffer[parser.buffer_pos] == ',' || parser.buffer[parser.buffer_pos] == '[' ||
+		parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '{' ||
+		parser.buffer[parser.buffer_pos] == '}' || parser.buffer[parser.buffer_pos] == '#' ||
+		parser.buffer[parser.buffer_pos] == '&' || parser.buffer[parser.buffer_pos] == '*' ||
+		parser.buffer[parser.buffer_pos] == '!' || parser.buffer[parser.buffer_pos] == '|' ||
+		parser.buffer[parser.buffer_pos] == '>' || parser.buffer[parser.buffer_pos] == '\'' ||
+		parser.buffer[parser.buffer_pos] == '"' || parser.buffer[parser.buffer_pos] == '%' ||
+		parser.buffer[parser.buffer_pos] == '@' || parser.buffer[parser.buffer_pos] == '`') ||
+		(parser.buffer[parser.buffer_pos] == '-' && !is_blank(parser.buffer, parser.buffer_pos+1)) ||
+		(parser.flow_level == 0 &&
+			(parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == ':') &&
+			!is_blankz(parser.buffer, parser.buffer_pos+1)) {
+		return yaml_parser_fetch_plain_scalar(parser)
+	}
+
+	// If we don't determine the token type so far, it is an error.
+	return yaml_parser_set_scanner_error(parser,
+		"while scanning for the next token", parser.mark,
+		"found character that cannot start any token")
+}
+
+// Check the list of potential simple keys and remove the positions that
+// cannot contain simple keys anymore.
+func yaml_parser_stale_simple_keys(parser *yaml_parser_t) bool {
+	// Check for a potential simple key for each flow level.
+	for i := range parser.simple_keys {
+		simple_key := &parser.simple_keys[i]
+
+		// The specification requires that a simple key
+		//
+		//  - is limited to a single line,
+		//  - is shorter than 1024 characters.
+		if simple_key.possible && (simple_key.mark.line < parser.mark.line || simple_key.mark.index+1024 < parser.mark.index) {
+
+			// Check if the potential simple key to be removed is required.
+			if simple_key.required {
+				return yaml_parser_set_scanner_error(parser,
+					"while scanning a simple key", simple_key.mark,
+					"could not find expected ':'")
+			}
+			simple_key.possible = false
+		}
+	}
+	return true
+}
+
+// Check if a simple key may start at the current position and add it if
+// needed.
+func yaml_parser_save_simple_key(parser *yaml_parser_t) bool {
+	// A simple key is required at the current position if the scanner is in
+	// the block context and the current column coincides with the indentation
+	// level.
+
+	required := parser.flow_level == 0 && parser.indent == parser.mark.column
+
+	//
+	// If the current position may start a simple key, save it.
+	//
+	if parser.simple_key_allowed {
+		simple_key := yaml_simple_key_t{
+			possible:     true,
+			required:     required,
+			token_number: parser.tokens_parsed + (len(parser.tokens) - parser.tokens_head),
+		}
+		simple_key.mark = parser.mark
+
+		if !yaml_parser_remove_simple_key(parser) {
+			return false
+		}
+		parser.simple_keys[len(parser.simple_keys)-1] = simple_key
+	}
+	return true
+}
+
+// Remove a potential simple key at the current flow level.
+func yaml_parser_remove_simple_key(parser *yaml_parser_t) bool {
+	i := len(parser.simple_keys) - 1
+	if parser.simple_keys[i].possible {
+		// If the key is required, it is an error.
+		if parser.simple_keys[i].required {
+			return yaml_parser_set_scanner_error(parser,
+				"while scanning a simple key", parser.simple_keys[i].mark,
+				"could not find expected ':'")
+		}
+	}
+	// Remove the key from the stack.
+	parser.simple_keys[i].possible = false
+	return true
+}
+
+// Increase the flow level and resize the simple key list if needed.
+func yaml_parser_increase_flow_level(parser *yaml_parser_t) bool {
+	// Reset the simple key on the next level.
+	parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{})
+
+	// Increase the flow level.
+	parser.flow_level++
+	return true
+}
+
+// Decrease the flow level.
+func yaml_parser_decrease_flow_level(parser *yaml_parser_t) bool {
+	if parser.flow_level > 0 {
+		parser.flow_level--
+		parser.simple_keys = parser.simple_keys[:len(parser.simple_keys)-1]
+	}
+	return true
+}
+
+// Push the current indentation level to the stack and set the new level
+// the current column is greater than the indentation level.  In this case,
+// append or insert the specified token into the token queue.
+func yaml_parser_roll_indent(parser *yaml_parser_t, column, number int, typ yaml_token_type_t, mark yaml_mark_t) bool {
+	// In the flow context, do nothing.
+	if parser.flow_level > 0 {
+		return true
+	}
+
+	if parser.indent < column {
+		// Push the current indentation level to the stack and set the new
+		// indentation level.
+		parser.indents = append(parser.indents, parser.indent)
+		parser.indent = column
+
+		// Create a token and insert it into the queue.
+		token := yaml_token_t{
+			typ:        typ,
+			start_mark: mark,
+			end_mark:   mark,
+		}
+		if number > -1 {
+			number -= parser.tokens_parsed
+		}
+		yaml_insert_token(parser, number, &token)
+	}
+	return true
+}
+
+// Pop indentation levels from the indents stack until the current level
+// becomes less or equal to the column.  For each indentation level, append
+// the BLOCK-END token.
+func yaml_parser_unroll_indent(parser *yaml_parser_t, column int) bool {
+	// In the flow context, do nothing.
+	if parser.flow_level > 0 {
+		return true
+	}
+
+	// Loop through the indentation levels in the stack.
+	for parser.indent > column {
+		// Create a token and append it to the queue.
+		token := yaml_token_t{
+			typ:        yaml_BLOCK_END_TOKEN,
+			start_mark: parser.mark,
+			end_mark:   parser.mark,
+		}
+		yaml_insert_token(parser, -1, &token)
+
+		// Pop the indentation level.
+		parser.indent = parser.indents[len(parser.indents)-1]
+		parser.indents = parser.indents[:len(parser.indents)-1]
+	}
+	return true
+}
+
+// Initialize the scanner and produce the STREAM-START token.
+func yaml_parser_fetch_stream_start(parser *yaml_parser_t) bool {
+
+	// Set the initial indentation.
+	parser.indent = -1
+
+	// Initialize the simple key stack.
+	parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{})
+
+	// A simple key is allowed at the beginning of the stream.
+	parser.simple_key_allowed = true
+
+	// We have started.
+	parser.stream_start_produced = true
+
+	// Create the STREAM-START token and append it to the queue.
+	token := yaml_token_t{
+		typ:        yaml_STREAM_START_TOKEN,
+		start_mark: parser.mark,
+		end_mark:   parser.mark,
+		encoding:   parser.encoding,
+	}
+	yaml_insert_token(parser, -1, &token)
+	return true
+}
+
+// Produce the STREAM-END token and shut down the scanner.
+func yaml_parser_fetch_stream_end(parser *yaml_parser_t) bool {
+
+	// Force new line.
+	if parser.mark.column != 0 {
+		parser.mark.column = 0
+		parser.mark.line++
+	}
+
+	// Reset the indentation level.
+	if !yaml_parser_unroll_indent(parser, -1) {
+		return false
+	}
+
+	// Reset simple keys.
+	if !yaml_parser_remove_simple_key(parser) {
+		return false
+	}
+
+	parser.simple_key_allowed = false
+
+	// Create the STREAM-END token and append it to the queue.
+	token := yaml_token_t{
+		typ:        yaml_STREAM_END_TOKEN,
+		start_mark: parser.mark,
+		end_mark:   parser.mark,
+	}
+	yaml_insert_token(parser, -1, &token)
+	return true
+}
+
+// Produce a VERSION-DIRECTIVE or TAG-DIRECTIVE token.
+func yaml_parser_fetch_directive(parser *yaml_parser_t) bool {
+	// Reset the indentation level.
+	if !yaml_parser_unroll_indent(parser, -1) {
+		return false
+	}
+
+	// Reset simple keys.
+	if !yaml_parser_remove_simple_key(parser) {
+		return false
+	}
+
+	parser.simple_key_allowed = false
+
+	// Create the YAML-DIRECTIVE or TAG-DIRECTIVE token.
+	token := yaml_token_t{}
+	if !yaml_parser_scan_directive(parser, &token) {
+		return false
+	}
+	// Append the token to the queue.
+	yaml_insert_token(parser, -1, &token)
+	return true
+}
+
+// Produce the DOCUMENT-START or DOCUMENT-END token.
+func yaml_parser_fetch_document_indicator(parser *yaml_parser_t, typ yaml_token_type_t) bool {
+	// Reset the indentation level.
+	if !yaml_parser_unroll_indent(parser, -1) {
+		return false
+	}
+
+	// Reset simple keys.
+	if !yaml_parser_remove_simple_key(parser) {
+		return false
+	}
+
+	parser.simple_key_allowed = false
+
+	// Consume the token.
+	start_mark := parser.mark
+
+	skip(parser)
+	skip(parser)
+	skip(parser)
+
+	end_mark := parser.mark
+
+	// Create the DOCUMENT-START or DOCUMENT-END token.
+	token := yaml_token_t{
+		typ:        typ,
+		start_mark: start_mark,
+		end_mark:   end_mark,
+	}
+	// Append the token to the queue.
+	yaml_insert_token(parser, -1, &token)
+	return true
+}
+
+// Produce the FLOW-SEQUENCE-START or FLOW-MAPPING-START token.
+func yaml_parser_fetch_flow_collection_start(parser *yaml_parser_t, typ yaml_token_type_t) bool {
+	// The indicators '[' and '{' may start a simple key.
+	if !yaml_parser_save_simple_key(parser) {
+		return false
+	}
+
+	// Increase the flow level.
+	if !yaml_parser_increase_flow_level(parser) {
+		return false
+	}
+
+	// A simple key may follow the indicators '[' and '{'.
+	parser.simple_key_allowed = true
+
+	// Consume the token.
+	start_mark := parser.mark
+	skip(parser)
+	end_mark := parser.mark
+
+	// Create the FLOW-SEQUENCE-START of FLOW-MAPPING-START token.
+	token := yaml_token_t{
+		typ:        typ,
+		start_mark: start_mark,
+		end_mark:   end_mark,
+	}
+	// Append the token to the queue.
+	yaml_insert_token(parser, -1, &token)
+	return true
+}
+
+// Produce the FLOW-SEQUENCE-END or FLOW-MAPPING-END token.
+func yaml_parser_fetch_flow_collection_end(parser *yaml_parser_t, typ yaml_token_type_t) bool {
+	// Reset any potential simple key on the current flow level.
+	if !yaml_parser_remove_simple_key(parser) {
+		return false
+	}
+
+	// Decrease the flow level.
+	if !yaml_parser_decrease_flow_level(parser) {
+		return false
+	}
+
+	// No simple keys after the indicators ']' and '}'.
+	parser.simple_key_allowed = false
+
+	// Consume the token.
+
+	start_mark := parser.mark
+	skip(parser)
+	end_mark := parser.mark
+
+	// Create the FLOW-SEQUENCE-END of FLOW-MAPPING-END token.
+	token := yaml_token_t{
+		typ:        typ,
+		start_mark: start_mark,
+		end_mark:   end_mark,
+	}
+	// Append the token to the queue.
+	yaml_insert_token(parser, -1, &token)
+	return true
+}
+
+// Produce the FLOW-ENTRY token.
+func yaml_parser_fetch_flow_entry(parser *yaml_parser_t) bool {
+	// Reset any potential simple keys on the current flow level.
+	if !yaml_parser_remove_simple_key(parser) {
+		return false
+	}
+
+	// Simple keys are allowed after ','.
+	parser.simple_key_allowed = true
+
+	// Consume the token.
+	start_mark := parser.mark
+	skip(parser)
+	end_mark := parser.mark
+
+	// Create the FLOW-ENTRY token and append it to the queue.
+	token := yaml_token_t{
+		typ:        yaml_FLOW_ENTRY_TOKEN,
+		start_mark: start_mark,
+		end_mark:   end_mark,
+	}
+	yaml_insert_token(parser, -1, &token)
+	return true
+}
+
+// Produce the BLOCK-ENTRY token.
+func yaml_parser_fetch_block_entry(parser *yaml_parser_t) bool {
+	// Check if the scanner is in the block context.
+	if parser.flow_level == 0 {
+		// Check if we are allowed to start a new entry.
+		if !parser.simple_key_allowed {
+			return yaml_parser_set_scanner_error(parser, "", parser.mark,
+				"block sequence entries are not allowed in this context")
+		}
+		// Add the BLOCK-SEQUENCE-START token if needed.
+		if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_SEQUENCE_START_TOKEN, parser.mark) {
+			return false
+		}
+	} else {
+		// It is an error for the '-' indicator to occur in the flow context,
+		// but we let the Parser detect and report about it because the Parser
+		// is able to point to the context.
+	}
+
+	// Reset any potential simple keys on the current flow level.
+	if !yaml_parser_remove_simple_key(parser) {
+		return false
+	}
+
+	// Simple keys are allowed after '-'.
+	parser.simple_key_allowed = true
+
+	// Consume the token.
+	start_mark := parser.mark
+	skip(parser)
+	end_mark := parser.mark
+
+	// Create the BLOCK-ENTRY token and append it to the queue.
+	token := yaml_token_t{
+		typ:        yaml_BLOCK_ENTRY_TOKEN,
+		start_mark: start_mark,
+		end_mark:   end_mark,
+	}
+	yaml_insert_token(parser, -1, &token)
+	return true
+}
+
+// Produce the KEY token.
+func yaml_parser_fetch_key(parser *yaml_parser_t) bool {
+
+	// In the block context, additional checks are required.
+	if parser.flow_level == 0 {
+		// Check if we are allowed to start a new key (not nessesary simple).
+		if !parser.simple_key_allowed {
+			return yaml_parser_set_scanner_error(parser, "", parser.mark,
+				"mapping keys are not allowed in this context")
+		}
+		// Add the BLOCK-MAPPING-START token if needed.
+		if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_MAPPING_START_TOKEN, parser.mark) {
+			return false
+		}
+	}
+
+	// Reset any potential simple keys on the current flow level.
+	if !yaml_parser_remove_simple_key(parser) {
+		return false
+	}
+
+	// Simple keys are allowed after '?' in the block context.
+	parser.simple_key_allowed = parser.flow_level == 0
+
+	// Consume the token.
+	start_mark := parser.mark
+	skip(parser)
+	end_mark := parser.mark
+
+	// Create the KEY token and append it to the queue.
+	token := yaml_token_t{
+		typ:        yaml_KEY_TOKEN,
+		start_mark: start_mark,
+		end_mark:   end_mark,
+	}
+	yaml_insert_token(parser, -1, &token)
+	return true
+}
+
+// Produce the VALUE token.
+func yaml_parser_fetch_value(parser *yaml_parser_t) bool {
+
+	simple_key := &parser.simple_keys[len(parser.simple_keys)-1]
+
+	// Have we found a simple key?
+	if simple_key.possible {
+		// Create the KEY token and insert it into the queue.
+		token := yaml_token_t{
+			typ:        yaml_KEY_TOKEN,
+			start_mark: simple_key.mark,
+			end_mark:   simple_key.mark,
+		}
+		yaml_insert_token(parser, simple_key.token_number-parser.tokens_parsed, &token)
+
+		// In the block context, we may need to add the BLOCK-MAPPING-START token.
+		if !yaml_parser_roll_indent(parser, simple_key.mark.column,
+			simple_key.token_number,
+			yaml_BLOCK_MAPPING_START_TOKEN, simple_key.mark) {
+			return false
+		}
+
+		// Remove the simple key.
+		simple_key.possible = false
+
+		// A simple key cannot follow another simple key.
+		parser.simple_key_allowed = false
+
+	} else {
+		// The ':' indicator follows a complex key.
+
+		// In the block context, extra checks are required.
+		if parser.flow_level == 0 {
+
+			// Check if we are allowed to start a complex value.
+			if !parser.simple_key_allowed {
+				return yaml_parser_set_scanner_error(parser, "", parser.mark,
+					"mapping values are not allowed in this context")
+			}
+
+			// Add the BLOCK-MAPPING-START token if needed.
+			if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_MAPPING_START_TOKEN, parser.mark) {
+				return false
+			}
+		}
+
+		// Simple keys after ':' are allowed in the block context.
+		parser.simple_key_allowed = parser.flow_level == 0
+	}
+
+	// Consume the token.
+	start_mark := parser.mark
+	skip(parser)
+	end_mark := parser.mark
+
+	// Create the VALUE token and append it to the queue.
+	token := yaml_token_t{
+		typ:        yaml_VALUE_TOKEN,
+		start_mark: start_mark,
+		end_mark:   end_mark,
+	}
+	yaml_insert_token(parser, -1, &token)
+	return true
+}
+
+// Produce the ALIAS or ANCHOR token.
+func yaml_parser_fetch_anchor(parser *yaml_parser_t, typ yaml_token_type_t) bool {
+	// An anchor or an alias could be a simple key.
+	if !yaml_parser_save_simple_key(parser) {
+		return false
+	}
+
+	// A simple key cannot follow an anchor or an alias.
+	parser.simple_key_allowed = false
+
+	// Create the ALIAS or ANCHOR token and append it to the queue.
+	var token yaml_token_t
+	if !yaml_parser_scan_anchor(parser, &token, typ) {
+		return false
+	}
+	yaml_insert_token(parser, -1, &token)
+	return true
+}
+
+// Produce the TAG token.
+func yaml_parser_fetch_tag(parser *yaml_parser_t) bool {
+	// A tag could be a simple key.
+	if !yaml_parser_save_simple_key(parser) {
+		return false
+	}
+
+	// A simple key cannot follow a tag.
+	parser.simple_key_allowed = false
+
+	// Create the TAG token and append it to the queue.
+	var token yaml_token_t
+	if !yaml_parser_scan_tag(parser, &token) {
+		return false
+	}
+	yaml_insert_token(parser, -1, &token)
+	return true
+}
+
+// Produce the SCALAR(...,literal) or SCALAR(...,folded) tokens.
+func yaml_parser_fetch_block_scalar(parser *yaml_parser_t, literal bool) bool {
+	// Remove any potential simple keys.
+	if !yaml_parser_remove_simple_key(parser) {
+		return false
+	}
+
+	// A simple key may follow a block scalar.
+	parser.simple_key_allowed = true
+
+	// Create the SCALAR token and append it to the queue.
+	var token yaml_token_t
+	if !yaml_parser_scan_block_scalar(parser, &token, literal) {
+		return false
+	}
+	yaml_insert_token(parser, -1, &token)
+	return true
+}
+
+// Produce the SCALAR(...,single-quoted) or SCALAR(...,double-quoted) tokens.
+func yaml_parser_fetch_flow_scalar(parser *yaml_parser_t, single bool) bool {
+	// A plain scalar could be a simple key.
+	if !yaml_parser_save_simple_key(parser) {
+		return false
+	}
+
+	// A simple key cannot follow a flow scalar.
+	parser.simple_key_allowed = false
+
+	// Create the SCALAR token and append it to the queue.
+	var token yaml_token_t
+	if !yaml_parser_scan_flow_scalar(parser, &token, single) {
+		return false
+	}
+	yaml_insert_token(parser, -1, &token)
+	return true
+}
+
+// Produce the SCALAR(...,plain) token.
+func yaml_parser_fetch_plain_scalar(parser *yaml_parser_t) bool {
+	// A plain scalar could be a simple key.
+	if !yaml_parser_save_simple_key(parser) {
+		return false
+	}
+
+	// A simple key cannot follow a flow scalar.
+	parser.simple_key_allowed = false
+
+	// Create the SCALAR token and append it to the queue.
+	var token yaml_token_t
+	if !yaml_parser_scan_plain_scalar(parser, &token) {
+		return false
+	}
+	yaml_insert_token(parser, -1, &token)
+	return true
+}
+
+// Eat whitespaces and comments until the next token is found.
+func yaml_parser_scan_to_next_token(parser *yaml_parser_t) bool {
+
+	// Until the next token is not found.
+	for {
+		// Allow the BOM mark to start a line.
+		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+			return false
+		}
+		if parser.mark.column == 0 && is_bom(parser.buffer, parser.buffer_pos) {
+			skip(parser)
+		}
+
+		// Eat whitespaces.
+		// Tabs are allowed:
+		//  - in the flow context
+		//  - in the block context, but not at the beginning of the line or
+		//  after '-', '?', or ':' (complex value).
+		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+			return false
+		}
+
+		for parser.buffer[parser.buffer_pos] == ' ' || ((parser.flow_level > 0 || !parser.simple_key_allowed) && parser.buffer[parser.buffer_pos] == '\t') {
+			skip(parser)
+			if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+				return false
+			}
+		}
+
+		// Eat a comment until a line break.
+		if parser.buffer[parser.buffer_pos] == '#' {
+			for !is_breakz(parser.buffer, parser.buffer_pos) {
+				skip(parser)
+				if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+					return false
+				}
+			}
+		}
+
+		// If it is a line break, eat it.
+		if is_break(parser.buffer, parser.buffer_pos) {
+			if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
+				return false
+			}
+			skip_line(parser)
+
+			// In the block context, a new line may start a simple key.
+			if parser.flow_level == 0 {
+				parser.simple_key_allowed = true
+			}
+		} else {
+			break // We have found a token.
+		}
+	}
+
+	return true
+}
+
+// Scan a YAML-DIRECTIVE or TAG-DIRECTIVE token.
+//
+// Scope:
+//      %YAML    1.1    # a comment \n
+//      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//      %TAG    !yaml!  tag:yaml.org,2002:  \n
+//      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//
+func yaml_parser_scan_directive(parser *yaml_parser_t, token *yaml_token_t) bool {
+	// Eat '%'.
+	start_mark := parser.mark
+	skip(parser)
+
+	// Scan the directive name.
+	var name []byte
+	if !yaml_parser_scan_directive_name(parser, start_mark, &name) {
+		return false
+	}
+
+	// Is it a YAML directive?
+	if bytes.Equal(name, []byte("YAML")) {
+		// Scan the VERSION directive value.
+		var major, minor int8
+		if !yaml_parser_scan_version_directive_value(parser, start_mark, &major, &minor) {
+			return false
+		}
+		end_mark := parser.mark
+
+		// Create a VERSION-DIRECTIVE token.
+		*token = yaml_token_t{
+			typ:        yaml_VERSION_DIRECTIVE_TOKEN,
+			start_mark: start_mark,
+			end_mark:   end_mark,
+			major:      major,
+			minor:      minor,
+		}
+
+		// Is it a TAG directive?
+	} else if bytes.Equal(name, []byte("TAG")) {
+		// Scan the TAG directive value.
+		var handle, prefix []byte
+		if !yaml_parser_scan_tag_directive_value(parser, start_mark, &handle, &prefix) {
+			return false
+		}
+		end_mark := parser.mark
+
+		// Create a TAG-DIRECTIVE token.
+		*token = yaml_token_t{
+			typ:        yaml_TAG_DIRECTIVE_TOKEN,
+			start_mark: start_mark,
+			end_mark:   end_mark,
+			value:      handle,
+			prefix:     prefix,
+		}
+
+		// Unknown directive.
+	} else {
+		yaml_parser_set_scanner_error(parser, "while scanning a directive",
+			start_mark, "found unknown directive name")
+		return false
+	}
+
+	// Eat the rest of the line including any comments.
+	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+		return false
+	}
+
+	for is_blank(parser.buffer, parser.buffer_pos) {
+		skip(parser)
+		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+			return false
+		}
+	}
+
+	if parser.buffer[parser.buffer_pos] == '#' {
+		for !is_breakz(parser.buffer, parser.buffer_pos) {
+			skip(parser)
+			if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+				return false
+			}
+		}
+	}
+
+	// Check if we are at the end of the line.
+	if !is_breakz(parser.buffer, parser.buffer_pos) {
+		yaml_parser_set_scanner_error(parser, "while scanning a directive",
+			start_mark, "did not find expected comment or line break")
+		return false
+	}
+
+	// Eat a line break.
+	if is_break(parser.buffer, parser.buffer_pos) {
+		if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
+			return false
+		}
+		skip_line(parser)
+	}
+
+	return true
+}
+
+// Scan the directive name.
+//
+// Scope:
+//      %YAML   1.1     # a comment \n
+//       ^^^^
+//      %TAG    !yaml!  tag:yaml.org,2002:  \n
+//       ^^^
+//
+func yaml_parser_scan_directive_name(parser *yaml_parser_t, start_mark yaml_mark_t, name *[]byte) bool {
+	// Consume the directive name.
+	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+		return false
+	}
+
+	var s []byte
+	for is_alpha(parser.buffer, parser.buffer_pos) {
+		s = read(parser, s)
+		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+			return false
+		}
+	}
+
+	// Check if the name is empty.
+	if len(s) == 0 {
+		yaml_parser_set_scanner_error(parser, "while scanning a directive",
+			start_mark, "could not find expected directive name")
+		return false
+	}
+
+	// Check for an blank character after the name.
+	if !is_blankz(parser.buffer, parser.buffer_pos) {
+		yaml_parser_set_scanner_error(parser, "while scanning a directive",
+			start_mark, "found unexpected non-alphabetical character")
+		return false
+	}
+	*name = s
+	return true
+}
+
+// Scan the value of VERSION-DIRECTIVE.
+//
+// Scope:
+//      %YAML   1.1     # a comment \n
+//           ^^^^^^
+func yaml_parser_scan_version_directive_value(parser *yaml_parser_t, start_mark yaml_mark_t, major, minor *int8) bool {
+	// Eat whitespaces.
+	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+		return false
+	}
+	for is_blank(parser.buffer, parser.buffer_pos) {
+		skip(parser)
+		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+			return false
+		}
+	}
+
+	// Consume the major version number.
+	if !yaml_parser_scan_version_directive_number(parser, start_mark, major) {
+		return false
+	}
+
+	// Eat '.'.
+	if parser.buffer[parser.buffer_pos] != '.' {
+		return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive",
+			start_mark, "did not find expected digit or '.' character")
+	}
+
+	skip(parser)
+
+	// Consume the minor version number.
+	if !yaml_parser_scan_version_directive_number(parser, start_mark, minor) {
+		return false
+	}
+	return true
+}
+
+const max_number_length = 2
+
+// Scan the version number of VERSION-DIRECTIVE.
+//
+// Scope:
+//      %YAML   1.1     # a comment \n
+//              ^
+//      %YAML   1.1     # a comment \n
+//                ^
+func yaml_parser_scan_version_directive_number(parser *yaml_parser_t, start_mark yaml_mark_t, number *int8) bool {
+
+	// Repeat while the next character is digit.
+	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+		return false
+	}
+	var value, length int8
+	for is_digit(parser.buffer, parser.buffer_pos) {
+		// Check if the number is too long.
+		length++
+		if length > max_number_length {
+			return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive",
+				start_mark, "found extremely long version number")
+		}
+		value = value*10 + int8(as_digit(parser.buffer, parser.buffer_pos))
+		skip(parser)
+		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+			return false
+		}
+	}
+
+	// Check if the number was present.
+	if length == 0 {
+		return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive",
+			start_mark, "did not find expected version number")
+	}
+	*number = value
+	return true
+}
+
+// Scan the value of a TAG-DIRECTIVE token.
+//
+// Scope:
+//      %TAG    !yaml!  tag:yaml.org,2002:  \n
+//          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//
+func yaml_parser_scan_tag_directive_value(parser *yaml_parser_t, start_mark yaml_mark_t, handle, prefix *[]byte) bool {
+	var handle_value, prefix_value []byte
+
+	// Eat whitespaces.
+	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+		return false
+	}
+
+	for is_blank(parser.buffer, parser.buffer_pos) {
+		skip(parser)
+		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+			return false
+		}
+	}
+
+	// Scan a handle.
+	if !yaml_parser_scan_tag_handle(parser, true, start_mark, &handle_value) {
+		return false
+	}
+
+	// Expect a whitespace.
+	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+		return false
+	}
+	if !is_blank(parser.buffer, parser.buffer_pos) {
+		yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive",
+			start_mark, "did not find expected whitespace")
+		return false
+	}
+
+	// Eat whitespaces.
+	for is_blank(parser.buffer, parser.buffer_pos) {
+		skip(parser)
+		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+			return false
+		}
+	}
+
+	// Scan a prefix.
+	if !yaml_parser_scan_tag_uri(parser, true, nil, start_mark, &prefix_value) {
+		return false
+	}
+
+	// Expect a whitespace or line break.
+	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+		return false
+	}
+	if !is_blankz(parser.buffer, parser.buffer_pos) {
+		yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive",
+			start_mark, "did not find expected whitespace or line break")
+		return false
+	}
+
+	*handle = handle_value
+	*prefix = prefix_value
+	return true
+}
+
+func yaml_parser_scan_anchor(parser *yaml_parser_t, token *yaml_token_t, typ yaml_token_type_t) bool {
+	var s []byte
+
+	// Eat the indicator character.
+	start_mark := parser.mark
+	skip(parser)
+
+	// Consume the value.
+	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+		return false
+	}
+
+	for is_alpha(parser.buffer, parser.buffer_pos) {
+		s = read(parser, s)
+		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+			return false
+		}
+	}
+
+	end_mark := parser.mark
+
+	/*
+	 * Check if length of the anchor is greater than 0 and it is followed by
+	 * a whitespace character or one of the indicators:
+	 *
+	 *      '?', ':', ',', ']', '}', '%', '@', '`'.
+	 */
+
+	if len(s) == 0 ||
+		!(is_blankz(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == '?' ||
+			parser.buffer[parser.buffer_pos] == ':' || parser.buffer[parser.buffer_pos] == ',' ||
+			parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '}' ||
+			parser.buffer[parser.buffer_pos] == '%' || parser.buffer[parser.buffer_pos] == '@' ||
+			parser.buffer[parser.buffer_pos] == '`') {
+		context := "while scanning an alias"
+		if typ == yaml_ANCHOR_TOKEN {
+			context = "while scanning an anchor"
+		}
+		yaml_parser_set_scanner_error(parser, context, start_mark,
+			"did not find expected alphabetic or numeric character")
+		return false
+	}
+
+	// Create a token.
+	*token = yaml_token_t{
+		typ:        typ,
+		start_mark: start_mark,
+		end_mark:   end_mark,
+		value:      s,
+	}
+
+	return true
+}
+
+/*
+ * Scan a TAG token.
+ */
+
+func yaml_parser_scan_tag(parser *yaml_parser_t, token *yaml_token_t) bool {
+	var handle, suffix []byte
+
+	start_mark := parser.mark
+
+	// Check if the tag is in the canonical form.
+	if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
+		return false
+	}
+
+	if parser.buffer[parser.buffer_pos+1] == '<' {
+		// Keep the handle as ''
+
+		// Eat '!<'
+		skip(parser)
+		skip(parser)
+
+		// Consume the tag value.
+		if !yaml_parser_scan_tag_uri(parser, false, nil, start_mark, &suffix) {
+			return false
+		}
+
+		// Check for '>' and eat it.
+		if parser.buffer[parser.buffer_pos] != '>' {
+			yaml_parser_set_scanner_error(parser, "while scanning a tag",
+				start_mark, "did not find the expected '>'")
+			return false
+		}
+
+		skip(parser)
+	} else {
+		// The tag has either the '!suffix' or the '!handle!suffix' form.
+
+		// First, try to scan a handle.
+		if !yaml_parser_scan_tag_handle(parser, false, start_mark, &handle) {
+			return false
+		}
+
+		// Check if it is, indeed, handle.
+		if handle[0] == '!' && len(handle) > 1 && handle[len(handle)-1] == '!' {
+			// Scan the suffix now.
+			if !yaml_parser_scan_tag_uri(parser, false, nil, start_mark, &suffix) {
+				return false
+			}
+		} else {
+			// It wasn't a handle after all.  Scan the rest of the tag.
+			if !yaml_parser_scan_tag_uri(parser, false, handle, start_mark, &suffix) {
+				return false
+			}
+
+			// Set the handle to '!'.
+			handle = []byte{'!'}
+
+			// A special case: the '!' tag.  Set the handle to '' and the
+			// suffix to '!'.
+			if len(suffix) == 0 {
+				handle, suffix = suffix, handle
+			}
+		}
+	}
+
+	// Check the character which ends the tag.
+	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+		return false
+	}
+	if !is_blankz(parser.buffer, parser.buffer_pos) {
+		yaml_parser_set_scanner_error(parser, "while scanning a tag",
+			start_mark, "did not find expected whitespace or line break")
+		return false
+	}
+
+	end_mark := parser.mark
+
+	// Create a token.
+	*token = yaml_token_t{
+		typ:        yaml_TAG_TOKEN,
+		start_mark: start_mark,
+		end_mark:   end_mark,
+		value:      handle,
+		suffix:     suffix,
+	}
+	return true
+}
+
+// Scan a tag handle.
+func yaml_parser_scan_tag_handle(parser *yaml_parser_t, directive bool, start_mark yaml_mark_t, handle *[]byte) bool {
+	// Check the initial '!' character.
+	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+		return false
+	}
+	if parser.buffer[parser.buffer_pos] != '!' {
+		yaml_parser_set_scanner_tag_error(parser, directive,
+			start_mark, "did not find expected '!'")
+		return false
+	}
+
+	var s []byte
+
+	// Copy the '!' character.
+	s = read(parser, s)
+
+	// Copy all subsequent alphabetical and numerical characters.
+	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+		return false
+	}
+	for is_alpha(parser.buffer, parser.buffer_pos) {
+		s = read(parser, s)
+		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+			return false
+		}
+	}
+
+	// Check if the trailing character is '!' and copy it.
+	if parser.buffer[parser.buffer_pos] == '!' {
+		s = read(parser, s)
+	} else {
+		// It's either the '!' tag or not really a tag handle.  If it's a %TAG
+		// directive, it's an error.  If it's a tag token, it must be a part of URI.
+		if directive && string(s) != "!" {
+			yaml_parser_set_scanner_tag_error(parser, directive,
+				start_mark, "did not find expected '!'")
+			return false
+		}
+	}
+
+	*handle = s
+	return true
+}
+
+// Scan a tag.
+func yaml_parser_scan_tag_uri(parser *yaml_parser_t, directive bool, head []byte, start_mark yaml_mark_t, uri *[]byte) bool {
+	//size_t length = head ? strlen((char *)head) : 0
+	var s []byte
+	hasTag := len(head) > 0
+
+	// Copy the head if needed.
+	//
+	// Note that we don't copy the leading '!' character.
+	if len(head) > 1 {
+		s = append(s, head[1:]...)
+	}
+
+	// Scan the tag.
+	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+		return false
+	}
+
+	// The set of characters that may appear in URI is as follows:
+	//
+	//      '0'-'9', 'A'-'Z', 'a'-'z', '_', '-', ';', '/', '?', ':', '@', '&',
+	//      '=', '+', '$', ',', '.', '!', '~', '*', '\'', '(', ')', '[', ']',
+	//      '%'.
+	// [Go] Convert this into more reasonable logic.
+	for is_alpha(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == ';' ||
+		parser.buffer[parser.buffer_pos] == '/' || parser.buffer[parser.buffer_pos] == '?' ||
+		parser.buffer[parser.buffer_pos] == ':' || parser.buffer[parser.buffer_pos] == '@' ||
+		parser.buffer[parser.buffer_pos] == '&' || parser.buffer[parser.buffer_pos] == '=' ||
+		parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '$' ||
+		parser.buffer[parser.buffer_pos] == ',' || parser.buffer[parser.buffer_pos] == '.' ||
+		parser.buffer[parser.buffer_pos] == '!' || parser.buffer[parser.buffer_pos] == '~' ||
+		parser.buffer[parser.buffer_pos] == '*' || parser.buffer[parser.buffer_pos] == '\'' ||
+		parser.buffer[parser.buffer_pos] == '(' || parser.buffer[parser.buffer_pos] == ')' ||
+		parser.buffer[parser.buffer_pos] == '[' || parser.buffer[parser.buffer_pos] == ']' ||
+		parser.buffer[parser.buffer_pos] == '%' {
+		// Check if it is a URI-escape sequence.
+		if parser.buffer[parser.buffer_pos] == '%' {
+			if !yaml_parser_scan_uri_escapes(parser, directive, start_mark, &s) {
+				return false
+			}
+		} else {
+			s = read(parser, s)
+		}
+		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+			return false
+		}
+		hasTag = true
+	}
+
+	if !hasTag {
+		yaml_parser_set_scanner_tag_error(parser, directive,
+			start_mark, "did not find expected tag URI")
+		return false
+	}
+	*uri = s
+	return true
+}
+
+// Decode an URI-escape sequence corresponding to a single UTF-8 character.
+func yaml_parser_scan_uri_escapes(parser *yaml_parser_t, directive bool, start_mark yaml_mark_t, s *[]byte) bool {
+
+	// Decode the required number of characters.
+	w := 1024
+	for w > 0 {
+		// Check for a URI-escaped octet.
+		if parser.unread < 3 && !yaml_parser_update_buffer(parser, 3) {
+			return false
+		}
+
+		if !(parser.buffer[parser.buffer_pos] == '%' &&
+			is_hex(parser.buffer, parser.buffer_pos+1) &&
+			is_hex(parser.buffer, parser.buffer_pos+2)) {
+			return yaml_parser_set_scanner_tag_error(parser, directive,
+				start_mark, "did not find URI escaped octet")
+		}
+
+		// Get the octet.
+		octet := byte((as_hex(parser.buffer, parser.buffer_pos+1) << 4) + as_hex(parser.buffer, parser.buffer_pos+2))
+
+		// If it is the leading octet, determine the length of the UTF-8 sequence.
+		if w == 1024 {
+			w = width(octet)
+			if w == 0 {
+				return yaml_parser_set_scanner_tag_error(parser, directive,
+					start_mark, "found an incorrect leading UTF-8 octet")
+			}
+		} else {
+			// Check if the trailing octet is correct.
+			if octet&0xC0 != 0x80 {
+				return yaml_parser_set_scanner_tag_error(parser, directive,
+					start_mark, "found an incorrect trailing UTF-8 octet")
+			}
+		}
+
+		// Copy the octet and move the pointers.
+		*s = append(*s, octet)
+		skip(parser)
+		skip(parser)
+		skip(parser)
+		w--
+	}
+	return true
+}
+
+// Scan a block scalar.
+func yaml_parser_scan_block_scalar(parser *yaml_parser_t, token *yaml_token_t, literal bool) bool {
+	// Eat the indicator '|' or '>'.
+	start_mark := parser.mark
+	skip(parser)
+
+	// Scan the additional block scalar indicators.
+	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+		return false
+	}
+
+	// Check for a chomping indicator.
+	var chomping, increment int
+	if parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '-' {
+		// Set the chomping method and eat the indicator.
+		if parser.buffer[parser.buffer_pos] == '+' {
+			chomping = +1
+		} else {
+			chomping = -1
+		}
+		skip(parser)
+
+		// Check for an indentation indicator.
+		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+			return false
+		}
+		if is_digit(parser.buffer, parser.buffer_pos) {
+			// Check that the indentation is greater than 0.
+			if parser.buffer[parser.buffer_pos] == '0' {
+				yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
+					start_mark, "found an indentation indicator equal to 0")
+				return false
+			}
+
+			// Get the indentation level and eat the indicator.
+			increment = as_digit(parser.buffer, parser.buffer_pos)
+			skip(parser)
+		}
+
+	} else if is_digit(parser.buffer, parser.buffer_pos) {
+		// Do the same as above, but in the opposite order.
+
+		if parser.buffer[parser.buffer_pos] == '0' {
+			yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
+				start_mark, "found an indentation indicator equal to 0")
+			return false
+		}
+		increment = as_digit(parser.buffer, parser.buffer_pos)
+		skip(parser)
+
+		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+			return false
+		}
+		if parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '-' {
+			if parser.buffer[parser.buffer_pos] == '+' {
+				chomping = +1
+			} else {
+				chomping = -1
+			}
+			skip(parser)
+		}
+	}
+
+	// Eat whitespaces and comments to the end of the line.
+	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+		return false
+	}
+	for is_blank(parser.buffer, parser.buffer_pos) {
+		skip(parser)
+		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+			return false
+		}
+	}
+	if parser.buffer[parser.buffer_pos] == '#' {
+		for !is_breakz(parser.buffer, parser.buffer_pos) {
+			skip(parser)
+			if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+				return false
+			}
+		}
+	}
+
+	// Check if we are at the end of the line.
+	if !is_breakz(parser.buffer, parser.buffer_pos) {
+		yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
+			start_mark, "did not find expected comment or line break")
+		return false
+	}
+
+	// Eat a line break.
+	if is_break(parser.buffer, parser.buffer_pos) {
+		if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
+			return false
+		}
+		skip_line(parser)
+	}
+
+	end_mark := parser.mark
+
+	// Set the indentation level if it was specified.
+	var indent int
+	if increment > 0 {
+		if parser.indent >= 0 {
+			indent = parser.indent + increment
+		} else {
+			indent = increment
+		}
+	}
+
+	// Scan the leading line breaks and determine the indentation level if needed.
+	var s, leading_break, trailing_breaks []byte
+	if !yaml_parser_scan_block_scalar_breaks(parser, &indent, &trailing_breaks, start_mark, &end_mark) {
+		return false
+	}
+
+	// Scan the block scalar content.
+	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+		return false
+	}
+	var leading_blank, trailing_blank bool
+	for parser.mark.column == indent && !is_z(parser.buffer, parser.buffer_pos) {
+		// We are at the beginning of a non-empty line.
+
+		// Is it a trailing whitespace?
+		trailing_blank = is_blank(parser.buffer, parser.buffer_pos)
+
+		// Check if we need to fold the leading line break.
+		if !literal && !leading_blank && !trailing_blank && len(leading_break) > 0 && leading_break[0] == '\n' {
+			// Do we need to join the lines by space?
+			if len(trailing_breaks) == 0 {
+				s = append(s, ' ')
+			}
+		} else {
+			s = append(s, leading_break...)
+		}
+		leading_break = leading_break[:0]
+
+		// Append the remaining line breaks.
+		s = append(s, trailing_breaks...)
+		trailing_breaks = trailing_breaks[:0]
+
+		// Is it a leading whitespace?
+		leading_blank = is_blank(parser.buffer, parser.buffer_pos)
+
+		// Consume the current line.
+		for !is_breakz(parser.buffer, parser.buffer_pos) {
+			s = read(parser, s)
+			if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+				return false
+			}
+		}
+
+		// Consume the line break.
+		if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
+			return false
+		}
+
+		leading_break = read_line(parser, leading_break)
+
+		// Eat the following indentation spaces and line breaks.
+		if !yaml_parser_scan_block_scalar_breaks(parser, &indent, &trailing_breaks, start_mark, &end_mark) {
+			return false
+		}
+	}
+
+	// Chomp the tail.
+	if chomping != -1 {
+		s = append(s, leading_break...)
+	}
+	if chomping == 1 {
+		s = append(s, trailing_breaks...)
+	}
+
+	// Create a token.
+	*token = yaml_token_t{
+		typ:        yaml_SCALAR_TOKEN,
+		start_mark: start_mark,
+		end_mark:   end_mark,
+		value:      s,
+		style:      yaml_LITERAL_SCALAR_STYLE,
+	}
+	if !literal {
+		token.style = yaml_FOLDED_SCALAR_STYLE
+	}
+	return true
+}
+
+// Scan indentation spaces and line breaks for a block scalar.  Determine the
+// indentation level if needed.
+func yaml_parser_scan_block_scalar_breaks(parser *yaml_parser_t, indent *int, breaks *[]byte, start_mark yaml_mark_t, end_mark *yaml_mark_t) bool {
+	*end_mark = parser.mark
+
+	// Eat the indentation spaces and line breaks.
+	max_indent := 0
+	for {
+		// Eat the indentation spaces.
+		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+			return false
+		}
+		for (*indent == 0 || parser.mark.column < *indent) && is_space(parser.buffer, parser.buffer_pos) {
+			skip(parser)
+			if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+				return false
+			}
+		}
+		if parser.mark.column > max_indent {
+			max_indent = parser.mark.column
+		}
+
+		// Check for a tab character messing the indentation.
+		if (*indent == 0 || parser.mark.column < *indent) && is_tab(parser.buffer, parser.buffer_pos) {
+			return yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
+				start_mark, "found a tab character where an indentation space is expected")
+		}
+
+		// Have we found a non-empty line?
+		if !is_break(parser.buffer, parser.buffer_pos) {
+			break
+		}
+
+		// Consume the line break.
+		if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
+			return false
+		}
+		// [Go] Should really be returning breaks instead.
+		*breaks = read_line(parser, *breaks)
+		*end_mark = parser.mark
+	}
+
+	// Determine the indentation level if needed.
+	if *indent == 0 {
+		*indent = max_indent
+		if *indent < parser.indent+1 {
+			*indent = parser.indent + 1
+		}
+		if *indent < 1 {
+			*indent = 1
+		}
+	}
+	return true
+}
+
+// Scan a quoted scalar.
+func yaml_parser_scan_flow_scalar(parser *yaml_parser_t, token *yaml_token_t, single bool) bool {
+	// Eat the left quote.
+	start_mark := parser.mark
+	skip(parser)
+
+	// Consume the content of the quoted scalar.
+	var s, leading_break, trailing_breaks, whitespaces []byte
+	for {
+		// Check that there are no document indicators at the beginning of the line.
+		if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) {
+			return false
+		}
+
+		if parser.mark.column == 0 &&
+			((parser.buffer[parser.buffer_pos+0] == '-' &&
+				parser.buffer[parser.buffer_pos+1] == '-' &&
+				parser.buffer[parser.buffer_pos+2] == '-') ||
+				(parser.buffer[parser.buffer_pos+0] == '.' &&
+					parser.buffer[parser.buffer_pos+1] == '.' &&
+					parser.buffer[parser.buffer_pos+2] == '.')) &&
+			is_blankz(parser.buffer, parser.buffer_pos+3) {
+			yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar",
+				start_mark, "found unexpected document indicator")
+			return false
+		}
+
+		// Check for EOF.
+		if is_z(parser.buffer, parser.buffer_pos) {
+			yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar",
+				start_mark, "found unexpected end of stream")
+			return false
+		}
+
+		// Consume non-blank characters.
+		leading_blanks := false
+		for !is_blankz(parser.buffer, parser.buffer_pos) {
+			if single && parser.buffer[parser.buffer_pos] == '\'' && parser.buffer[parser.buffer_pos+1] == '\'' {
+				// Is is an escaped single quote.
+				s = append(s, '\'')
+				skip(parser)
+				skip(parser)
+
+			} else if single && parser.buffer[parser.buffer_pos] == '\'' {
+				// It is a right single quote.
+				break
+			} else if !single && parser.buffer[parser.buffer_pos] == '"' {
+				// It is a right double quote.
+				break
+
+			} else if !single && parser.buffer[parser.buffer_pos] == '\\' && is_break(parser.buffer, parser.buffer_pos+1) {
+				// It is an escaped line break.
+				if parser.unread < 3 && !yaml_parser_update_buffer(parser, 3) {
+					return false
+				}
+				skip(parser)
+				skip_line(parser)
+				leading_blanks = true
+				break
+
+			} else if !single && parser.buffer[parser.buffer_pos] == '\\' {
+				// It is an escape sequence.
+				code_length := 0
+
+				// Check the escape character.
+				switch parser.buffer[parser.buffer_pos+1] {
+				case '0':
+					s = append(s, 0)
+				case 'a':
+					s = append(s, '\x07')
+				case 'b':
+					s = append(s, '\x08')
+				case 't', '\t':
+					s = append(s, '\x09')
+				case 'n':
+					s = append(s, '\x0A')
+				case 'v':
+					s = append(s, '\x0B')
+				case 'f':
+					s = append(s, '\x0C')
+				case 'r':
+					s = append(s, '\x0D')
+				case 'e':
+					s = append(s, '\x1B')
+				case ' ':
+					s = append(s, '\x20')
+				case '"':
+					s = append(s, '"')
+				case '\'':
+					s = append(s, '\'')
+				case '\\':
+					s = append(s, '\\')
+				case 'N': // NEL (#x85)
+					s = append(s, '\xC2')
+					s = append(s, '\x85')
+				case '_': // #xA0
+					s = append(s, '\xC2')
+					s = append(s, '\xA0')
+				case 'L': // LS (#x2028)
+					s = append(s, '\xE2')
+					s = append(s, '\x80')
+					s = append(s, '\xA8')
+				case 'P': // PS (#x2029)
+					s = append(s, '\xE2')
+					s = append(s, '\x80')
+					s = append(s, '\xA9')
+				case 'x':
+					code_length = 2
+				case 'u':
+					code_length = 4
+				case 'U':
+					code_length = 8
+				default:
+					yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar",
+						start_mark, "found unknown escape character")
+					return false
+				}
+
+				skip(parser)
+				skip(parser)
+
+				// Consume an arbitrary escape code.
+				if code_length > 0 {
+					var value int
+
+					// Scan the character value.
+					if parser.unread < code_length && !yaml_parser_update_buffer(parser, code_length) {
+						return false
+					}
+					for k := 0; k < code_length; k++ {
+						if !is_hex(parser.buffer, parser.buffer_pos+k) {
+							yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar",
+								start_mark, "did not find expected hexdecimal number")
+							return false
+						}
+						value = (value << 4) + as_hex(parser.buffer, parser.buffer_pos+k)
+					}
+
+					// Check the value and write the character.
+					if (value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF {
+						yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar",
+							start_mark, "found invalid Unicode character escape code")
+						return false
+					}
+					if value <= 0x7F {
+						s = append(s, byte(value))
+					} else if value <= 0x7FF {
+						s = append(s, byte(0xC0+(value>>6)))
+						s = append(s, byte(0x80+(value&0x3F)))
+					} else if value <= 0xFFFF {
+						s = append(s, byte(0xE0+(value>>12)))
+						s = append(s, byte(0x80+((value>>6)&0x3F)))
+						s = append(s, byte(0x80+(value&0x3F)))
+					} else {
+						s = append(s, byte(0xF0+(value>>18)))
+						s = append(s, byte(0x80+((value>>12)&0x3F)))
+						s = append(s, byte(0x80+((value>>6)&0x3F)))
+						s = append(s, byte(0x80+(value&0x3F)))
+					}
+
+					// Advance the pointer.
+					for k := 0; k < code_length; k++ {
+						skip(parser)
+					}
+				}
+			} else {
+				// It is a non-escaped non-blank character.
+				s = read(parser, s)
+			}
+			if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
+				return false
+			}
+		}
+
+		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+			return false
+		}
+
+		// Check if we are at the end of the scalar.
+		if single {
+			if parser.buffer[parser.buffer_pos] == '\'' {
+				break
+			}
+		} else {
+			if parser.buffer[parser.buffer_pos] == '"' {
+				break
+			}
+		}
+
+		// Consume blank characters.
+		for is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos) {
+			if is_blank(parser.buffer, parser.buffer_pos) {
+				// Consume a space or a tab character.
+				if !leading_blanks {
+					whitespaces = read(parser, whitespaces)
+				} else {
+					skip(parser)
+				}
+			} else {
+				if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
+					return false
+				}
+
+				// Check if it is a first line break.
+				if !leading_blanks {
+					whitespaces = whitespaces[:0]
+					leading_break = read_line(parser, leading_break)
+					leading_blanks = true
+				} else {
+					trailing_breaks = read_line(parser, trailing_breaks)
+				}
+			}
+			if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+				return false
+			}
+		}
+
+		// Join the whitespaces or fold line breaks.
+		if leading_blanks {
+			// Do we need to fold line breaks?
+			if len(leading_break) > 0 && leading_break[0] == '\n' {
+				if len(trailing_breaks) == 0 {
+					s = append(s, ' ')
+				} else {
+					s = append(s, trailing_breaks...)
+				}
+			} else {
+				s = append(s, leading_break...)
+				s = append(s, trailing_breaks...)
+			}
+			trailing_breaks = trailing_breaks[:0]
+			leading_break = leading_break[:0]
+		} else {
+			s = append(s, whitespaces...)
+			whitespaces = whitespaces[:0]
+		}
+	}
+
+	// Eat the right quote.
+	skip(parser)
+	end_mark := parser.mark
+
+	// Create a token.
+	*token = yaml_token_t{
+		typ:        yaml_SCALAR_TOKEN,
+		start_mark: start_mark,
+		end_mark:   end_mark,
+		value:      s,
+		style:      yaml_SINGLE_QUOTED_SCALAR_STYLE,
+	}
+	if !single {
+		token.style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
+	}
+	return true
+}
+
+// Scan a plain scalar.
+func yaml_parser_scan_plain_scalar(parser *yaml_parser_t, token *yaml_token_t) bool {
+
+	var s, leading_break, trailing_breaks, whitespaces []byte
+	var leading_blanks bool
+	var indent = parser.indent + 1
+
+	start_mark := parser.mark
+	end_mark := parser.mark
+
+	// Consume the content of the plain scalar.
+	for {
+		// Check for a document indicator.
+		if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) {
+			return false
+		}
+		if parser.mark.column == 0 &&
+			((parser.buffer[parser.buffer_pos+0] == '-' &&
+				parser.buffer[parser.buffer_pos+1] == '-' &&
+				parser.buffer[parser.buffer_pos+2] == '-') ||
+				(parser.buffer[parser.buffer_pos+0] == '.' &&
+					parser.buffer[parser.buffer_pos+1] == '.' &&
+					parser.buffer[parser.buffer_pos+2] == '.')) &&
+			is_blankz(parser.buffer, parser.buffer_pos+3) {
+			break
+		}
+
+		// Check for a comment.
+		if parser.buffer[parser.buffer_pos] == '#' {
+			break
+		}
+
+		// Consume non-blank characters.
+		for !is_blankz(parser.buffer, parser.buffer_pos) {
+
+			// Check for indicators that may end a plain scalar.
+			if (parser.buffer[parser.buffer_pos] == ':' && is_blankz(parser.buffer, parser.buffer_pos+1)) ||
+				(parser.flow_level > 0 &&
+					(parser.buffer[parser.buffer_pos] == ',' ||
+						parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == '[' ||
+						parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '{' ||
+						parser.buffer[parser.buffer_pos] == '}')) {
+				break
+			}
+
+			// Check if we need to join whitespaces and breaks.
+			if leading_blanks || len(whitespaces) > 0 {
+				if leading_blanks {
+					// Do we need to fold line breaks?
+					if leading_break[0] == '\n' {
+						if len(trailing_breaks) == 0 {
+							s = append(s, ' ')
+						} else {
+							s = append(s, trailing_breaks...)
+						}
+					} else {
+						s = append(s, leading_break...)
+						s = append(s, trailing_breaks...)
+					}
+					trailing_breaks = trailing_breaks[:0]
+					leading_break = leading_break[:0]
+					leading_blanks = false
+				} else {
+					s = append(s, whitespaces...)
+					whitespaces = whitespaces[:0]
+				}
+			}
+
+			// Copy the character.
+			s = read(parser, s)
+
+			end_mark = parser.mark
+			if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
+				return false
+			}
+		}
+
+		// Is it the end?
+		if !(is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos)) {
+			break
+		}
+
+		// Consume blank characters.
+		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+			return false
+		}
+
+		for is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos) {
+			if is_blank(parser.buffer, parser.buffer_pos) {
+
+				// Check for tab characters that abuse indentation.
+				if leading_blanks && parser.mark.column < indent && is_tab(parser.buffer, parser.buffer_pos) {
+					yaml_parser_set_scanner_error(parser, "while scanning a plain scalar",
+						start_mark, "found a tab character that violates indentation")
+					return false
+				}
+
+				// Consume a space or a tab character.
+				if !leading_blanks {
+					whitespaces = read(parser, whitespaces)
+				} else {
+					skip(parser)
+				}
+			} else {
+				if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
+					return false
+				}
+
+				// Check if it is a first line break.
+				if !leading_blanks {
+					whitespaces = whitespaces[:0]
+					leading_break = read_line(parser, leading_break)
+					leading_blanks = true
+				} else {
+					trailing_breaks = read_line(parser, trailing_breaks)
+				}
+			}
+			if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+				return false
+			}
+		}
+
+		// Check indentation level.
+		if parser.flow_level == 0 && parser.mark.column < indent {
+			break
+		}
+	}
+
+	// Create a token.
+	*token = yaml_token_t{
+		typ:        yaml_SCALAR_TOKEN,
+		start_mark: start_mark,
+		end_mark:   end_mark,
+		value:      s,
+		style:      yaml_PLAIN_SCALAR_STYLE,
+	}
+
+	// Note that we change the 'simple_key_allowed' flag.
+	if leading_blanks {
+		parser.simple_key_allowed = true
+	}
+	return true
+}

+ 113 - 0
vendor/gopkg.in/yaml.v2/sorter.go

@@ -0,0 +1,113 @@
+package yaml
+
+import (
+	"reflect"
+	"unicode"
+)
+
+type keyList []reflect.Value
+
+func (l keyList) Len() int      { return len(l) }
+func (l keyList) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
+func (l keyList) Less(i, j int) bool {
+	a := l[i]
+	b := l[j]
+	ak := a.Kind()
+	bk := b.Kind()
+	for (ak == reflect.Interface || ak == reflect.Ptr) && !a.IsNil() {
+		a = a.Elem()
+		ak = a.Kind()
+	}
+	for (bk == reflect.Interface || bk == reflect.Ptr) && !b.IsNil() {
+		b = b.Elem()
+		bk = b.Kind()
+	}
+	af, aok := keyFloat(a)
+	bf, bok := keyFloat(b)
+	if aok && bok {
+		if af != bf {
+			return af < bf
+		}
+		if ak != bk {
+			return ak < bk
+		}
+		return numLess(a, b)
+	}
+	if ak != reflect.String || bk != reflect.String {
+		return ak < bk
+	}
+	ar, br := []rune(a.String()), []rune(b.String())
+	for i := 0; i < len(ar) && i < len(br); i++ {
+		if ar[i] == br[i] {
+			continue
+		}
+		al := unicode.IsLetter(ar[i])
+		bl := unicode.IsLetter(br[i])
+		if al && bl {
+			return ar[i] < br[i]
+		}
+		if al || bl {
+			return bl
+		}
+		var ai, bi int
+		var an, bn int64
+		if ar[i] == '0' || br[i] == '0' {
+			for j := i-1; j >= 0 && unicode.IsDigit(ar[j]); j-- {
+				if ar[j] != '0' {
+					an = 1
+					bn = 1
+					break
+				}
+			}
+		}
+		for ai = i; ai < len(ar) && unicode.IsDigit(ar[ai]); ai++ {
+			an = an*10 + int64(ar[ai]-'0')
+		}
+		for bi = i; bi < len(br) && unicode.IsDigit(br[bi]); bi++ {
+			bn = bn*10 + int64(br[bi]-'0')
+		}
+		if an != bn {
+			return an < bn
+		}
+		if ai != bi {
+			return ai < bi
+		}
+		return ar[i] < br[i]
+	}
+	return len(ar) < len(br)
+}
+
+// keyFloat returns a float value for v if it is a number/bool
+// and whether it is a number/bool or not.
+func keyFloat(v reflect.Value) (f float64, ok bool) {
+	switch v.Kind() {
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		return float64(v.Int()), true
+	case reflect.Float32, reflect.Float64:
+		return v.Float(), true
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+		return float64(v.Uint()), true
+	case reflect.Bool:
+		if v.Bool() {
+			return 1, true
+		}
+		return 0, true
+	}
+	return 0, false
+}
+
+// numLess returns whether a < b.
+// a and b must necessarily have the same kind.
+func numLess(a, b reflect.Value) bool {
+	switch a.Kind() {
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		return a.Int() < b.Int()
+	case reflect.Float32, reflect.Float64:
+		return a.Float() < b.Float()
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+		return a.Uint() < b.Uint()
+	case reflect.Bool:
+		return !a.Bool() && b.Bool()
+	}
+	panic("not a number")
+}

+ 26 - 0
vendor/gopkg.in/yaml.v2/writerc.go

@@ -0,0 +1,26 @@
+package yaml
+
+// Set the writer error and return false.
+func yaml_emitter_set_writer_error(emitter *yaml_emitter_t, problem string) bool {
+	emitter.error = yaml_WRITER_ERROR
+	emitter.problem = problem
+	return false
+}
+
+// Flush the output buffer.
+func yaml_emitter_flush(emitter *yaml_emitter_t) bool {
+	if emitter.write_handler == nil {
+		panic("write handler not set")
+	}
+
+	// Check if the buffer is empty.
+	if emitter.buffer_pos == 0 {
+		return true
+	}
+
+	if err := emitter.write_handler(emitter, emitter.buffer[:emitter.buffer_pos]); err != nil {
+		return yaml_emitter_set_writer_error(emitter, "write error: "+err.Error())
+	}
+	emitter.buffer_pos = 0
+	return true
+}

+ 466 - 0
vendor/gopkg.in/yaml.v2/yaml.go

@@ -0,0 +1,466 @@
+// Package yaml implements YAML support for the Go language.
+//
+// Source code and other details for the project are available at GitHub:
+//
+//   https://github.com/go-yaml/yaml
+//
+package yaml
+
+import (
+	"errors"
+	"fmt"
+	"io"
+	"reflect"
+	"strings"
+	"sync"
+)
+
+// MapSlice encodes and decodes as a YAML map.
+// The order of keys is preserved when encoding and decoding.
+type MapSlice []MapItem
+
+// MapItem is an item in a MapSlice.
+type MapItem struct {
+	Key, Value interface{}
+}
+
+// The Unmarshaler interface may be implemented by types to customize their
+// behavior when being unmarshaled from a YAML document. The UnmarshalYAML
+// method receives a function that may be called to unmarshal the original
+// YAML value into a field or variable. It is safe to call the unmarshal
+// function parameter more than once if necessary.
+type Unmarshaler interface {
+	UnmarshalYAML(unmarshal func(interface{}) error) error
+}
+
+// The Marshaler interface may be implemented by types to customize their
+// behavior when being marshaled into a YAML document. The returned value
+// is marshaled in place of the original value implementing Marshaler.
+//
+// If an error is returned by MarshalYAML, the marshaling procedure stops
+// and returns with the provided error.
+type Marshaler interface {
+	MarshalYAML() (interface{}, error)
+}
+
+// Unmarshal decodes the first document found within the in byte slice
+// and assigns decoded values into the out value.
+//
+// Maps and pointers (to a struct, string, int, etc) are accepted as out
+// values. If an internal pointer within a struct is not initialized,
+// the yaml package will initialize it if necessary for unmarshalling
+// the provided data. The out parameter must not be nil.
+//
+// The type of the decoded values should be compatible with the respective
+// values in out. If one or more values cannot be decoded due to a type
+// mismatches, decoding continues partially until the end of the YAML
+// content, and a *yaml.TypeError is returned with details for all
+// missed values.
+//
+// Struct fields are only unmarshalled if they are exported (have an
+// upper case first letter), and are unmarshalled using the field name
+// lowercased as the default key. Custom keys may be defined via the
+// "yaml" name in the field tag: the content preceding the first comma
+// is used as the key, and the following comma-separated options are
+// used to tweak the marshalling process (see Marshal).
+// Conflicting names result in a runtime error.
+//
+// For example:
+//
+//     type T struct {
+//         F int `yaml:"a,omitempty"`
+//         B int
+//     }
+//     var t T
+//     yaml.Unmarshal([]byte("a: 1\nb: 2"), &t)
+//
+// See the documentation of Marshal for the format of tags and a list of
+// supported tag options.
+//
+func Unmarshal(in []byte, out interface{}) (err error) {
+	return unmarshal(in, out, false)
+}
+
+// UnmarshalStrict is like Unmarshal except that any fields that are found
+// in the data that do not have corresponding struct members, or mapping
+// keys that are duplicates, will result in
+// an error.
+func UnmarshalStrict(in []byte, out interface{}) (err error) {
+	return unmarshal(in, out, true)
+}
+
+// A Decorder reads and decodes YAML values from an input stream.
+type Decoder struct {
+	strict bool
+	parser *parser
+}
+
+// NewDecoder returns a new decoder that reads from r.
+//
+// The decoder introduces its own buffering and may read
+// data from r beyond the YAML values requested.
+func NewDecoder(r io.Reader) *Decoder {
+	return &Decoder{
+		parser: newParserFromReader(r),
+	}
+}
+
+// SetStrict sets whether strict decoding behaviour is enabled when
+// decoding items in the data (see UnmarshalStrict). By default, decoding is not strict.
+func (dec *Decoder) SetStrict(strict bool) {
+	dec.strict = strict
+}
+
+// Decode reads the next YAML-encoded value from its input
+// and stores it in the value pointed to by v.
+//
+// See the documentation for Unmarshal for details about the
+// conversion of YAML into a Go value.
+func (dec *Decoder) Decode(v interface{}) (err error) {
+	d := newDecoder(dec.strict)
+	defer handleErr(&err)
+	node := dec.parser.parse()
+	if node == nil {
+		return io.EOF
+	}
+	out := reflect.ValueOf(v)
+	if out.Kind() == reflect.Ptr && !out.IsNil() {
+		out = out.Elem()
+	}
+	d.unmarshal(node, out)
+	if len(d.terrors) > 0 {
+		return &TypeError{d.terrors}
+	}
+	return nil
+}
+
+func unmarshal(in []byte, out interface{}, strict bool) (err error) {
+	defer handleErr(&err)
+	d := newDecoder(strict)
+	p := newParser(in)
+	defer p.destroy()
+	node := p.parse()
+	if node != nil {
+		v := reflect.ValueOf(out)
+		if v.Kind() == reflect.Ptr && !v.IsNil() {
+			v = v.Elem()
+		}
+		d.unmarshal(node, v)
+	}
+	if len(d.terrors) > 0 {
+		return &TypeError{d.terrors}
+	}
+	return nil
+}
+
+// Marshal serializes the value provided into a YAML document. The structure
+// of the generated document will reflect the structure of the value itself.
+// Maps and pointers (to struct, string, int, etc) are accepted as the in value.
+//
+// Struct fields are only marshalled if they are exported (have an upper case
+// first letter), and are marshalled using the field name lowercased as the
+// default key. Custom keys may be defined via the "yaml" name in the field
+// tag: the content preceding the first comma is used as the key, and the
+// following comma-separated options are used to tweak the marshalling process.
+// Conflicting names result in a runtime error.
+//
+// The field tag format accepted is:
+//
+//     `(...) yaml:"[<key>][,<flag1>[,<flag2>]]" (...)`
+//
+// The following flags are currently supported:
+//
+//     omitempty    Only include the field if it's not set to the zero
+//                  value for the type or to empty slices or maps.
+//                  Zero valued structs will be omitted if all their public
+//                  fields are zero, unless they implement an IsZero
+//                  method (see the IsZeroer interface type), in which
+//                  case the field will be included if that method returns true.
+//
+//     flow         Marshal using a flow style (useful for structs,
+//                  sequences and maps).
+//
+//     inline       Inline the field, which must be a struct or a map,
+//                  causing all of its fields or keys to be processed as if
+//                  they were part of the outer struct. For maps, keys must
+//                  not conflict with the yaml keys of other struct fields.
+//
+// In addition, if the key is "-", the field is ignored.
+//
+// For example:
+//
+//     type T struct {
+//         F int `yaml:"a,omitempty"`
+//         B int
+//     }
+//     yaml.Marshal(&T{B: 2}) // Returns "b: 2\n"
+//     yaml.Marshal(&T{F: 1}} // Returns "a: 1\nb: 0\n"
+//
+func Marshal(in interface{}) (out []byte, err error) {
+	defer handleErr(&err)
+	e := newEncoder()
+	defer e.destroy()
+	e.marshalDoc("", reflect.ValueOf(in))
+	e.finish()
+	out = e.out
+	return
+}
+
+// An Encoder writes YAML values to an output stream.
+type Encoder struct {
+	encoder *encoder
+}
+
+// NewEncoder returns a new encoder that writes to w.
+// The Encoder should be closed after use to flush all data
+// to w.
+func NewEncoder(w io.Writer) *Encoder {
+	return &Encoder{
+		encoder: newEncoderWithWriter(w),
+	}
+}
+
+// Encode writes the YAML encoding of v to the stream.
+// If multiple items are encoded to the stream, the
+// second and subsequent document will be preceded
+// with a "---" document separator, but the first will not.
+//
+// See the documentation for Marshal for details about the conversion of Go
+// values to YAML.
+func (e *Encoder) Encode(v interface{}) (err error) {
+	defer handleErr(&err)
+	e.encoder.marshalDoc("", reflect.ValueOf(v))
+	return nil
+}
+
+// Close closes the encoder by writing any remaining data.
+// It does not write a stream terminating string "...".
+func (e *Encoder) Close() (err error) {
+	defer handleErr(&err)
+	e.encoder.finish()
+	return nil
+}
+
+func handleErr(err *error) {
+	if v := recover(); v != nil {
+		if e, ok := v.(yamlError); ok {
+			*err = e.err
+		} else {
+			panic(v)
+		}
+	}
+}
+
+type yamlError struct {
+	err error
+}
+
+func fail(err error) {
+	panic(yamlError{err})
+}
+
+func failf(format string, args ...interface{}) {
+	panic(yamlError{fmt.Errorf("yaml: "+format, args...)})
+}
+
+// A TypeError is returned by Unmarshal when one or more fields in
+// the YAML document cannot be properly decoded into the requested
+// types. When this error is returned, the value is still
+// unmarshaled partially.
+type TypeError struct {
+	Errors []string
+}
+
+func (e *TypeError) Error() string {
+	return fmt.Sprintf("yaml: unmarshal errors:\n  %s", strings.Join(e.Errors, "\n  "))
+}
+
+// --------------------------------------------------------------------------
+// Maintain a mapping of keys to structure field indexes
+
+// The code in this section was copied from mgo/bson.
+
+// structInfo holds details for the serialization of fields of
+// a given struct.
+type structInfo struct {
+	FieldsMap  map[string]fieldInfo
+	FieldsList []fieldInfo
+
+	// InlineMap is the number of the field in the struct that
+	// contains an ,inline map, or -1 if there's none.
+	InlineMap int
+}
+
+type fieldInfo struct {
+	Key       string
+	Num       int
+	OmitEmpty bool
+	Flow      bool
+	// Id holds the unique field identifier, so we can cheaply
+	// check for field duplicates without maintaining an extra map.
+	Id int
+
+	// Inline holds the field index if the field is part of an inlined struct.
+	Inline []int
+}
+
+var structMap = make(map[reflect.Type]*structInfo)
+var fieldMapMutex sync.RWMutex
+
+func getStructInfo(st reflect.Type) (*structInfo, error) {
+	fieldMapMutex.RLock()
+	sinfo, found := structMap[st]
+	fieldMapMutex.RUnlock()
+	if found {
+		return sinfo, nil
+	}
+
+	n := st.NumField()
+	fieldsMap := make(map[string]fieldInfo)
+	fieldsList := make([]fieldInfo, 0, n)
+	inlineMap := -1
+	for i := 0; i != n; i++ {
+		field := st.Field(i)
+		if field.PkgPath != "" && !field.Anonymous {
+			continue // Private field
+		}
+
+		info := fieldInfo{Num: i}
+
+		tag := field.Tag.Get("yaml")
+		if tag == "" && strings.Index(string(field.Tag), ":") < 0 {
+			tag = string(field.Tag)
+		}
+		if tag == "-" {
+			continue
+		}
+
+		inline := false
+		fields := strings.Split(tag, ",")
+		if len(fields) > 1 {
+			for _, flag := range fields[1:] {
+				switch flag {
+				case "omitempty":
+					info.OmitEmpty = true
+				case "flow":
+					info.Flow = true
+				case "inline":
+					inline = true
+				default:
+					return nil, errors.New(fmt.Sprintf("Unsupported flag %q in tag %q of type %s", flag, tag, st))
+				}
+			}
+			tag = fields[0]
+		}
+
+		if inline {
+			switch field.Type.Kind() {
+			case reflect.Map:
+				if inlineMap >= 0 {
+					return nil, errors.New("Multiple ,inline maps in struct " + st.String())
+				}
+				if field.Type.Key() != reflect.TypeOf("") {
+					return nil, errors.New("Option ,inline needs a map with string keys in struct " + st.String())
+				}
+				inlineMap = info.Num
+			case reflect.Struct:
+				sinfo, err := getStructInfo(field.Type)
+				if err != nil {
+					return nil, err
+				}
+				for _, finfo := range sinfo.FieldsList {
+					if _, found := fieldsMap[finfo.Key]; found {
+						msg := "Duplicated key '" + finfo.Key + "' in struct " + st.String()
+						return nil, errors.New(msg)
+					}
+					if finfo.Inline == nil {
+						finfo.Inline = []int{i, finfo.Num}
+					} else {
+						finfo.Inline = append([]int{i}, finfo.Inline...)
+					}
+					finfo.Id = len(fieldsList)
+					fieldsMap[finfo.Key] = finfo
+					fieldsList = append(fieldsList, finfo)
+				}
+			default:
+				//return nil, errors.New("Option ,inline needs a struct value or map field")
+				return nil, errors.New("Option ,inline needs a struct value field")
+			}
+			continue
+		}
+
+		if tag != "" {
+			info.Key = tag
+		} else {
+			info.Key = strings.ToLower(field.Name)
+		}
+
+		if _, found = fieldsMap[info.Key]; found {
+			msg := "Duplicated key '" + info.Key + "' in struct " + st.String()
+			return nil, errors.New(msg)
+		}
+
+		info.Id = len(fieldsList)
+		fieldsList = append(fieldsList, info)
+		fieldsMap[info.Key] = info
+	}
+
+	sinfo = &structInfo{
+		FieldsMap:  fieldsMap,
+		FieldsList: fieldsList,
+		InlineMap:  inlineMap,
+	}
+
+	fieldMapMutex.Lock()
+	structMap[st] = sinfo
+	fieldMapMutex.Unlock()
+	return sinfo, nil
+}
+
+// IsZeroer is used to check whether an object is zero to
+// determine whether it should be omitted when marshaling
+// with the omitempty flag. One notable implementation
+// is time.Time.
+type IsZeroer interface {
+	IsZero() bool
+}
+
+func isZero(v reflect.Value) bool {
+	kind := v.Kind()
+	if z, ok := v.Interface().(IsZeroer); ok {
+		if (kind == reflect.Ptr || kind == reflect.Interface) && v.IsNil() {
+			return true
+		}
+		return z.IsZero()
+	}
+	switch kind {
+	case reflect.String:
+		return len(v.String()) == 0
+	case reflect.Interface, reflect.Ptr:
+		return v.IsNil()
+	case reflect.Slice:
+		return v.Len() == 0
+	case reflect.Map:
+		return v.Len() == 0
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		return v.Int() == 0
+	case reflect.Float32, reflect.Float64:
+		return v.Float() == 0
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+		return v.Uint() == 0
+	case reflect.Bool:
+		return !v.Bool()
+	case reflect.Struct:
+		vt := v.Type()
+		for i := v.NumField() - 1; i >= 0; i-- {
+			if vt.Field(i).PkgPath != "" {
+				continue // Private field
+			}
+			if !isZero(v.Field(i)) {
+				return false
+			}
+		}
+		return true
+	}
+	return false
+}

+ 738 - 0
vendor/gopkg.in/yaml.v2/yamlh.go

@@ -0,0 +1,738 @@
+package yaml
+
+import (
+	"fmt"
+	"io"
+)
+
+// The version directive data.
+type yaml_version_directive_t struct {
+	major int8 // The major version number.
+	minor int8 // The minor version number.
+}
+
+// The tag directive data.
+type yaml_tag_directive_t struct {
+	handle []byte // The tag handle.
+	prefix []byte // The tag prefix.
+}
+
+type yaml_encoding_t int
+
+// The stream encoding.
+const (
+	// Let the parser choose the encoding.
+	yaml_ANY_ENCODING yaml_encoding_t = iota
+
+	yaml_UTF8_ENCODING    // The default UTF-8 encoding.
+	yaml_UTF16LE_ENCODING // The UTF-16-LE encoding with BOM.
+	yaml_UTF16BE_ENCODING // The UTF-16-BE encoding with BOM.
+)
+
+type yaml_break_t int
+
+// Line break types.
+const (
+	// Let the parser choose the break type.
+	yaml_ANY_BREAK yaml_break_t = iota
+
+	yaml_CR_BREAK   // Use CR for line breaks (Mac style).
+	yaml_LN_BREAK   // Use LN for line breaks (Unix style).
+	yaml_CRLN_BREAK // Use CR LN for line breaks (DOS style).
+)
+
+type yaml_error_type_t int
+
+// Many bad things could happen with the parser and emitter.
+const (
+	// No error is produced.
+	yaml_NO_ERROR yaml_error_type_t = iota
+
+	yaml_MEMORY_ERROR   // Cannot allocate or reallocate a block of memory.
+	yaml_READER_ERROR   // Cannot read or decode the input stream.
+	yaml_SCANNER_ERROR  // Cannot scan the input stream.
+	yaml_PARSER_ERROR   // Cannot parse the input stream.
+	yaml_COMPOSER_ERROR // Cannot compose a YAML document.
+	yaml_WRITER_ERROR   // Cannot write to the output stream.
+	yaml_EMITTER_ERROR  // Cannot emit a YAML stream.
+)
+
+// The pointer position.
+type yaml_mark_t struct {
+	index  int // The position index.
+	line   int // The position line.
+	column int // The position column.
+}
+
+// Node Styles
+
+type yaml_style_t int8
+
+type yaml_scalar_style_t yaml_style_t
+
+// Scalar styles.
+const (
+	// Let the emitter choose the style.
+	yaml_ANY_SCALAR_STYLE yaml_scalar_style_t = iota
+
+	yaml_PLAIN_SCALAR_STYLE         // The plain scalar style.
+	yaml_SINGLE_QUOTED_SCALAR_STYLE // The single-quoted scalar style.
+	yaml_DOUBLE_QUOTED_SCALAR_STYLE // The double-quoted scalar style.
+	yaml_LITERAL_SCALAR_STYLE       // The literal scalar style.
+	yaml_FOLDED_SCALAR_STYLE        // The folded scalar style.
+)
+
+type yaml_sequence_style_t yaml_style_t
+
+// Sequence styles.
+const (
+	// Let the emitter choose the style.
+	yaml_ANY_SEQUENCE_STYLE yaml_sequence_style_t = iota
+
+	yaml_BLOCK_SEQUENCE_STYLE // The block sequence style.
+	yaml_FLOW_SEQUENCE_STYLE  // The flow sequence style.
+)
+
+type yaml_mapping_style_t yaml_style_t
+
+// Mapping styles.
+const (
+	// Let the emitter choose the style.
+	yaml_ANY_MAPPING_STYLE yaml_mapping_style_t = iota
+
+	yaml_BLOCK_MAPPING_STYLE // The block mapping style.
+	yaml_FLOW_MAPPING_STYLE  // The flow mapping style.
+)
+
+// Tokens
+
+type yaml_token_type_t int
+
+// Token types.
+const (
+	// An empty token.
+	yaml_NO_TOKEN yaml_token_type_t = iota
+
+	yaml_STREAM_START_TOKEN // A STREAM-START token.
+	yaml_STREAM_END_TOKEN   // A STREAM-END token.
+
+	yaml_VERSION_DIRECTIVE_TOKEN // A VERSION-DIRECTIVE token.
+	yaml_TAG_DIRECTIVE_TOKEN     // A TAG-DIRECTIVE token.
+	yaml_DOCUMENT_START_TOKEN    // A DOCUMENT-START token.
+	yaml_DOCUMENT_END_TOKEN      // A DOCUMENT-END token.
+
+	yaml_BLOCK_SEQUENCE_START_TOKEN // A BLOCK-SEQUENCE-START token.
+	yaml_BLOCK_MAPPING_START_TOKEN  // A BLOCK-SEQUENCE-END token.
+	yaml_BLOCK_END_TOKEN            // A BLOCK-END token.
+
+	yaml_FLOW_SEQUENCE_START_TOKEN // A FLOW-SEQUENCE-START token.
+	yaml_FLOW_SEQUENCE_END_TOKEN   // A FLOW-SEQUENCE-END token.
+	yaml_FLOW_MAPPING_START_TOKEN  // A FLOW-MAPPING-START token.
+	yaml_FLOW_MAPPING_END_TOKEN    // A FLOW-MAPPING-END token.
+
+	yaml_BLOCK_ENTRY_TOKEN // A BLOCK-ENTRY token.
+	yaml_FLOW_ENTRY_TOKEN  // A FLOW-ENTRY token.
+	yaml_KEY_TOKEN         // A KEY token.
+	yaml_VALUE_TOKEN       // A VALUE token.
+
+	yaml_ALIAS_TOKEN  // An ALIAS token.
+	yaml_ANCHOR_TOKEN // An ANCHOR token.
+	yaml_TAG_TOKEN    // A TAG token.
+	yaml_SCALAR_TOKEN // A SCALAR token.
+)
+
+func (tt yaml_token_type_t) String() string {
+	switch tt {
+	case yaml_NO_TOKEN:
+		return "yaml_NO_TOKEN"
+	case yaml_STREAM_START_TOKEN:
+		return "yaml_STREAM_START_TOKEN"
+	case yaml_STREAM_END_TOKEN:
+		return "yaml_STREAM_END_TOKEN"
+	case yaml_VERSION_DIRECTIVE_TOKEN:
+		return "yaml_VERSION_DIRECTIVE_TOKEN"
+	case yaml_TAG_DIRECTIVE_TOKEN:
+		return "yaml_TAG_DIRECTIVE_TOKEN"
+	case yaml_DOCUMENT_START_TOKEN:
+		return "yaml_DOCUMENT_START_TOKEN"
+	case yaml_DOCUMENT_END_TOKEN:
+		return "yaml_DOCUMENT_END_TOKEN"
+	case yaml_BLOCK_SEQUENCE_START_TOKEN:
+		return "yaml_BLOCK_SEQUENCE_START_TOKEN"
+	case yaml_BLOCK_MAPPING_START_TOKEN:
+		return "yaml_BLOCK_MAPPING_START_TOKEN"
+	case yaml_BLOCK_END_TOKEN:
+		return "yaml_BLOCK_END_TOKEN"
+	case yaml_FLOW_SEQUENCE_START_TOKEN:
+		return "yaml_FLOW_SEQUENCE_START_TOKEN"
+	case yaml_FLOW_SEQUENCE_END_TOKEN:
+		return "yaml_FLOW_SEQUENCE_END_TOKEN"
+	case yaml_FLOW_MAPPING_START_TOKEN:
+		return "yaml_FLOW_MAPPING_START_TOKEN"
+	case yaml_FLOW_MAPPING_END_TOKEN:
+		return "yaml_FLOW_MAPPING_END_TOKEN"
+	case yaml_BLOCK_ENTRY_TOKEN:
+		return "yaml_BLOCK_ENTRY_TOKEN"
+	case yaml_FLOW_ENTRY_TOKEN:
+		return "yaml_FLOW_ENTRY_TOKEN"
+	case yaml_KEY_TOKEN:
+		return "yaml_KEY_TOKEN"
+	case yaml_VALUE_TOKEN:
+		return "yaml_VALUE_TOKEN"
+	case yaml_ALIAS_TOKEN:
+		return "yaml_ALIAS_TOKEN"
+	case yaml_ANCHOR_TOKEN:
+		return "yaml_ANCHOR_TOKEN"
+	case yaml_TAG_TOKEN:
+		return "yaml_TAG_TOKEN"
+	case yaml_SCALAR_TOKEN:
+		return "yaml_SCALAR_TOKEN"
+	}
+	return "<unknown token>"
+}
+
+// The token structure.
+type yaml_token_t struct {
+	// The token type.
+	typ yaml_token_type_t
+
+	// The start/end of the token.
+	start_mark, end_mark yaml_mark_t
+
+	// The stream encoding (for yaml_STREAM_START_TOKEN).
+	encoding yaml_encoding_t
+
+	// The alias/anchor/scalar value or tag/tag directive handle
+	// (for yaml_ALIAS_TOKEN, yaml_ANCHOR_TOKEN, yaml_SCALAR_TOKEN, yaml_TAG_TOKEN, yaml_TAG_DIRECTIVE_TOKEN).
+	value []byte
+
+	// The tag suffix (for yaml_TAG_TOKEN).
+	suffix []byte
+
+	// The tag directive prefix (for yaml_TAG_DIRECTIVE_TOKEN).
+	prefix []byte
+
+	// The scalar style (for yaml_SCALAR_TOKEN).
+	style yaml_scalar_style_t
+
+	// The version directive major/minor (for yaml_VERSION_DIRECTIVE_TOKEN).
+	major, minor int8
+}
+
+// Events
+
+type yaml_event_type_t int8
+
+// Event types.
+const (
+	// An empty event.
+	yaml_NO_EVENT yaml_event_type_t = iota
+
+	yaml_STREAM_START_EVENT   // A STREAM-START event.
+	yaml_STREAM_END_EVENT     // A STREAM-END event.
+	yaml_DOCUMENT_START_EVENT // A DOCUMENT-START event.
+	yaml_DOCUMENT_END_EVENT   // A DOCUMENT-END event.
+	yaml_ALIAS_EVENT          // An ALIAS event.
+	yaml_SCALAR_EVENT         // A SCALAR event.
+	yaml_SEQUENCE_START_EVENT // A SEQUENCE-START event.
+	yaml_SEQUENCE_END_EVENT   // A SEQUENCE-END event.
+	yaml_MAPPING_START_EVENT  // A MAPPING-START event.
+	yaml_MAPPING_END_EVENT    // A MAPPING-END event.
+)
+
+var eventStrings = []string{
+	yaml_NO_EVENT:             "none",
+	yaml_STREAM_START_EVENT:   "stream start",
+	yaml_STREAM_END_EVENT:     "stream end",
+	yaml_DOCUMENT_START_EVENT: "document start",
+	yaml_DOCUMENT_END_EVENT:   "document end",
+	yaml_ALIAS_EVENT:          "alias",
+	yaml_SCALAR_EVENT:         "scalar",
+	yaml_SEQUENCE_START_EVENT: "sequence start",
+	yaml_SEQUENCE_END_EVENT:   "sequence end",
+	yaml_MAPPING_START_EVENT:  "mapping start",
+	yaml_MAPPING_END_EVENT:    "mapping end",
+}
+
+func (e yaml_event_type_t) String() string {
+	if e < 0 || int(e) >= len(eventStrings) {
+		return fmt.Sprintf("unknown event %d", e)
+	}
+	return eventStrings[e]
+}
+
+// The event structure.
+type yaml_event_t struct {
+
+	// The event type.
+	typ yaml_event_type_t
+
+	// The start and end of the event.
+	start_mark, end_mark yaml_mark_t
+
+	// The document encoding (for yaml_STREAM_START_EVENT).
+	encoding yaml_encoding_t
+
+	// The version directive (for yaml_DOCUMENT_START_EVENT).
+	version_directive *yaml_version_directive_t
+
+	// The list of tag directives (for yaml_DOCUMENT_START_EVENT).
+	tag_directives []yaml_tag_directive_t
+
+	// The anchor (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT, yaml_ALIAS_EVENT).
+	anchor []byte
+
+	// The tag (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT).
+	tag []byte
+
+	// The scalar value (for yaml_SCALAR_EVENT).
+	value []byte
+
+	// Is the document start/end indicator implicit, or the tag optional?
+	// (for yaml_DOCUMENT_START_EVENT, yaml_DOCUMENT_END_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT, yaml_SCALAR_EVENT).
+	implicit bool
+
+	// Is the tag optional for any non-plain style? (for yaml_SCALAR_EVENT).
+	quoted_implicit bool
+
+	// The style (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT).
+	style yaml_style_t
+}
+
+func (e *yaml_event_t) scalar_style() yaml_scalar_style_t     { return yaml_scalar_style_t(e.style) }
+func (e *yaml_event_t) sequence_style() yaml_sequence_style_t { return yaml_sequence_style_t(e.style) }
+func (e *yaml_event_t) mapping_style() yaml_mapping_style_t   { return yaml_mapping_style_t(e.style) }
+
+// Nodes
+
+const (
+	yaml_NULL_TAG      = "tag:yaml.org,2002:null"      // The tag !!null with the only possible value: null.
+	yaml_BOOL_TAG      = "tag:yaml.org,2002:bool"      // The tag !!bool with the values: true and false.
+	yaml_STR_TAG       = "tag:yaml.org,2002:str"       // The tag !!str for string values.
+	yaml_INT_TAG       = "tag:yaml.org,2002:int"       // The tag !!int for integer values.
+	yaml_FLOAT_TAG     = "tag:yaml.org,2002:float"     // The tag !!float for float values.
+	yaml_TIMESTAMP_TAG = "tag:yaml.org,2002:timestamp" // The tag !!timestamp for date and time values.
+
+	yaml_SEQ_TAG = "tag:yaml.org,2002:seq" // The tag !!seq is used to denote sequences.
+	yaml_MAP_TAG = "tag:yaml.org,2002:map" // The tag !!map is used to denote mapping.
+
+	// Not in original libyaml.
+	yaml_BINARY_TAG = "tag:yaml.org,2002:binary"
+	yaml_MERGE_TAG  = "tag:yaml.org,2002:merge"
+
+	yaml_DEFAULT_SCALAR_TAG   = yaml_STR_TAG // The default scalar tag is !!str.
+	yaml_DEFAULT_SEQUENCE_TAG = yaml_SEQ_TAG // The default sequence tag is !!seq.
+	yaml_DEFAULT_MAPPING_TAG  = yaml_MAP_TAG // The default mapping tag is !!map.
+)
+
+type yaml_node_type_t int
+
+// Node types.
+const (
+	// An empty node.
+	yaml_NO_NODE yaml_node_type_t = iota
+
+	yaml_SCALAR_NODE   // A scalar node.
+	yaml_SEQUENCE_NODE // A sequence node.
+	yaml_MAPPING_NODE  // A mapping node.
+)
+
+// An element of a sequence node.
+type yaml_node_item_t int
+
+// An element of a mapping node.
+type yaml_node_pair_t struct {
+	key   int // The key of the element.
+	value int // The value of the element.
+}
+
+// The node structure.
+type yaml_node_t struct {
+	typ yaml_node_type_t // The node type.
+	tag []byte           // The node tag.
+
+	// The node data.
+
+	// The scalar parameters (for yaml_SCALAR_NODE).
+	scalar struct {
+		value  []byte              // The scalar value.
+		length int                 // The length of the scalar value.
+		style  yaml_scalar_style_t // The scalar style.
+	}
+
+	// The sequence parameters (for YAML_SEQUENCE_NODE).
+	sequence struct {
+		items_data []yaml_node_item_t    // The stack of sequence items.
+		style      yaml_sequence_style_t // The sequence style.
+	}
+
+	// The mapping parameters (for yaml_MAPPING_NODE).
+	mapping struct {
+		pairs_data  []yaml_node_pair_t   // The stack of mapping pairs (key, value).
+		pairs_start *yaml_node_pair_t    // The beginning of the stack.
+		pairs_end   *yaml_node_pair_t    // The end of the stack.
+		pairs_top   *yaml_node_pair_t    // The top of the stack.
+		style       yaml_mapping_style_t // The mapping style.
+	}
+
+	start_mark yaml_mark_t // The beginning of the node.
+	end_mark   yaml_mark_t // The end of the node.
+
+}
+
+// The document structure.
+type yaml_document_t struct {
+
+	// The document nodes.
+	nodes []yaml_node_t
+
+	// The version directive.
+	version_directive *yaml_version_directive_t
+
+	// The list of tag directives.
+	tag_directives_data  []yaml_tag_directive_t
+	tag_directives_start int // The beginning of the tag directives list.
+	tag_directives_end   int // The end of the tag directives list.
+
+	start_implicit int // Is the document start indicator implicit?
+	end_implicit   int // Is the document end indicator implicit?
+
+	// The start/end of the document.
+	start_mark, end_mark yaml_mark_t
+}
+
+// The prototype of a read handler.
+//
+// The read handler is called when the parser needs to read more bytes from the
+// source. The handler should write not more than size bytes to the buffer.
+// The number of written bytes should be set to the size_read variable.
+//
+// [in,out]   data        A pointer to an application data specified by
+//                        yaml_parser_set_input().
+// [out]      buffer      The buffer to write the data from the source.
+// [in]       size        The size of the buffer.
+// [out]      size_read   The actual number of bytes read from the source.
+//
+// On success, the handler should return 1.  If the handler failed,
+// the returned value should be 0. On EOF, the handler should set the
+// size_read to 0 and return 1.
+type yaml_read_handler_t func(parser *yaml_parser_t, buffer []byte) (n int, err error)
+
+// This structure holds information about a potential simple key.
+type yaml_simple_key_t struct {
+	possible     bool        // Is a simple key possible?
+	required     bool        // Is a simple key required?
+	token_number int         // The number of the token.
+	mark         yaml_mark_t // The position mark.
+}
+
+// The states of the parser.
+type yaml_parser_state_t int
+
+const (
+	yaml_PARSE_STREAM_START_STATE yaml_parser_state_t = iota
+
+	yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE           // Expect the beginning of an implicit document.
+	yaml_PARSE_DOCUMENT_START_STATE                    // Expect DOCUMENT-START.
+	yaml_PARSE_DOCUMENT_CONTENT_STATE                  // Expect the content of a document.
+	yaml_PARSE_DOCUMENT_END_STATE                      // Expect DOCUMENT-END.
+	yaml_PARSE_BLOCK_NODE_STATE                        // Expect a block node.
+	yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE // Expect a block node or indentless sequence.
+	yaml_PARSE_FLOW_NODE_STATE                         // Expect a flow node.
+	yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE        // Expect the first entry of a block sequence.
+	yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE              // Expect an entry of a block sequence.
+	yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE         // Expect an entry of an indentless sequence.
+	yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE           // Expect the first key of a block mapping.
+	yaml_PARSE_BLOCK_MAPPING_KEY_STATE                 // Expect a block mapping key.
+	yaml_PARSE_BLOCK_MAPPING_VALUE_STATE               // Expect a block mapping value.
+	yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE         // Expect the first entry of a flow sequence.
+	yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE               // Expect an entry of a flow sequence.
+	yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE   // Expect a key of an ordered mapping.
+	yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE // Expect a value of an ordered mapping.
+	yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE   // Expect the and of an ordered mapping entry.
+	yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE            // Expect the first key of a flow mapping.
+	yaml_PARSE_FLOW_MAPPING_KEY_STATE                  // Expect a key of a flow mapping.
+	yaml_PARSE_FLOW_MAPPING_VALUE_STATE                // Expect a value of a flow mapping.
+	yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE          // Expect an empty value of a flow mapping.
+	yaml_PARSE_END_STATE                               // Expect nothing.
+)
+
+func (ps yaml_parser_state_t) String() string {
+	switch ps {
+	case yaml_PARSE_STREAM_START_STATE:
+		return "yaml_PARSE_STREAM_START_STATE"
+	case yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE:
+		return "yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE"
+	case yaml_PARSE_DOCUMENT_START_STATE:
+		return "yaml_PARSE_DOCUMENT_START_STATE"
+	case yaml_PARSE_DOCUMENT_CONTENT_STATE:
+		return "yaml_PARSE_DOCUMENT_CONTENT_STATE"
+	case yaml_PARSE_DOCUMENT_END_STATE:
+		return "yaml_PARSE_DOCUMENT_END_STATE"
+	case yaml_PARSE_BLOCK_NODE_STATE:
+		return "yaml_PARSE_BLOCK_NODE_STATE"
+	case yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE:
+		return "yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE"
+	case yaml_PARSE_FLOW_NODE_STATE:
+		return "yaml_PARSE_FLOW_NODE_STATE"
+	case yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE:
+		return "yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE"
+	case yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE:
+		return "yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE"
+	case yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE:
+		return "yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE"
+	case yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE:
+		return "yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE"
+	case yaml_PARSE_BLOCK_MAPPING_KEY_STATE:
+		return "yaml_PARSE_BLOCK_MAPPING_KEY_STATE"
+	case yaml_PARSE_BLOCK_MAPPING_VALUE_STATE:
+		return "yaml_PARSE_BLOCK_MAPPING_VALUE_STATE"
+	case yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE:
+		return "yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE"
+	case yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE:
+		return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE"
+	case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE:
+		return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE"
+	case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE:
+		return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE"
+	case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE:
+		return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE"
+	case yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE:
+		return "yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE"
+	case yaml_PARSE_FLOW_MAPPING_KEY_STATE:
+		return "yaml_PARSE_FLOW_MAPPING_KEY_STATE"
+	case yaml_PARSE_FLOW_MAPPING_VALUE_STATE:
+		return "yaml_PARSE_FLOW_MAPPING_VALUE_STATE"
+	case yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE:
+		return "yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE"
+	case yaml_PARSE_END_STATE:
+		return "yaml_PARSE_END_STATE"
+	}
+	return "<unknown parser state>"
+}
+
+// This structure holds aliases data.
+type yaml_alias_data_t struct {
+	anchor []byte      // The anchor.
+	index  int         // The node id.
+	mark   yaml_mark_t // The anchor mark.
+}
+
+// The parser structure.
+//
+// All members are internal. Manage the structure using the
+// yaml_parser_ family of functions.
+type yaml_parser_t struct {
+
+	// Error handling
+
+	error yaml_error_type_t // Error type.
+
+	problem string // Error description.
+
+	// The byte about which the problem occurred.
+	problem_offset int
+	problem_value  int
+	problem_mark   yaml_mark_t
+
+	// The error context.
+	context      string
+	context_mark yaml_mark_t
+
+	// Reader stuff
+
+	read_handler yaml_read_handler_t // Read handler.
+
+	input_reader io.Reader // File input data.
+	input        []byte    // String input data.
+	input_pos    int
+
+	eof bool // EOF flag
+
+	buffer     []byte // The working buffer.
+	buffer_pos int    // The current position of the buffer.
+
+	unread int // The number of unread characters in the buffer.
+
+	raw_buffer     []byte // The raw buffer.
+	raw_buffer_pos int    // The current position of the buffer.
+
+	encoding yaml_encoding_t // The input encoding.
+
+	offset int         // The offset of the current position (in bytes).
+	mark   yaml_mark_t // The mark of the current position.
+
+	// Scanner stuff
+
+	stream_start_produced bool // Have we started to scan the input stream?
+	stream_end_produced   bool // Have we reached the end of the input stream?
+
+	flow_level int // The number of unclosed '[' and '{' indicators.
+
+	tokens          []yaml_token_t // The tokens queue.
+	tokens_head     int            // The head of the tokens queue.
+	tokens_parsed   int            // The number of tokens fetched from the queue.
+	token_available bool           // Does the tokens queue contain a token ready for dequeueing.
+
+	indent  int   // The current indentation level.
+	indents []int // The indentation levels stack.
+
+	simple_key_allowed bool                // May a simple key occur at the current position?
+	simple_keys        []yaml_simple_key_t // The stack of simple keys.
+
+	// Parser stuff
+
+	state          yaml_parser_state_t    // The current parser state.
+	states         []yaml_parser_state_t  // The parser states stack.
+	marks          []yaml_mark_t          // The stack of marks.
+	tag_directives []yaml_tag_directive_t // The list of TAG directives.
+
+	// Dumper stuff
+
+	aliases []yaml_alias_data_t // The alias data.
+
+	document *yaml_document_t // The currently parsed document.
+}
+
+// Emitter Definitions
+
+// The prototype of a write handler.
+//
+// The write handler is called when the emitter needs to flush the accumulated
+// characters to the output.  The handler should write @a size bytes of the
+// @a buffer to the output.
+//
+// @param[in,out]   data        A pointer to an application data specified by
+//                              yaml_emitter_set_output().
+// @param[in]       buffer      The buffer with bytes to be written.
+// @param[in]       size        The size of the buffer.
+//
+// @returns On success, the handler should return @c 1.  If the handler failed,
+// the returned value should be @c 0.
+//
+type yaml_write_handler_t func(emitter *yaml_emitter_t, buffer []byte) error
+
+type yaml_emitter_state_t int
+
+// The emitter states.
+const (
+	// Expect STREAM-START.
+	yaml_EMIT_STREAM_START_STATE yaml_emitter_state_t = iota
+
+	yaml_EMIT_FIRST_DOCUMENT_START_STATE       // Expect the first DOCUMENT-START or STREAM-END.
+	yaml_EMIT_DOCUMENT_START_STATE             // Expect DOCUMENT-START or STREAM-END.
+	yaml_EMIT_DOCUMENT_CONTENT_STATE           // Expect the content of a document.
+	yaml_EMIT_DOCUMENT_END_STATE               // Expect DOCUMENT-END.
+	yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE   // Expect the first item of a flow sequence.
+	yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE         // Expect an item of a flow sequence.
+	yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE     // Expect the first key of a flow mapping.
+	yaml_EMIT_FLOW_MAPPING_KEY_STATE           // Expect a key of a flow mapping.
+	yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE  // Expect a value for a simple key of a flow mapping.
+	yaml_EMIT_FLOW_MAPPING_VALUE_STATE         // Expect a value of a flow mapping.
+	yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE  // Expect the first item of a block sequence.
+	yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE        // Expect an item of a block sequence.
+	yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE    // Expect the first key of a block mapping.
+	yaml_EMIT_BLOCK_MAPPING_KEY_STATE          // Expect the key of a block mapping.
+	yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE // Expect a value for a simple key of a block mapping.
+	yaml_EMIT_BLOCK_MAPPING_VALUE_STATE        // Expect a value of a block mapping.
+	yaml_EMIT_END_STATE                        // Expect nothing.
+)
+
+// The emitter structure.
+//
+// All members are internal.  Manage the structure using the @c yaml_emitter_
+// family of functions.
+type yaml_emitter_t struct {
+
+	// Error handling
+
+	error   yaml_error_type_t // Error type.
+	problem string            // Error description.
+
+	// Writer stuff
+
+	write_handler yaml_write_handler_t // Write handler.
+
+	output_buffer *[]byte   // String output data.
+	output_writer io.Writer // File output data.
+
+	buffer     []byte // The working buffer.
+	buffer_pos int    // The current position of the buffer.
+
+	raw_buffer     []byte // The raw buffer.
+	raw_buffer_pos int    // The current position of the buffer.
+
+	encoding yaml_encoding_t // The stream encoding.
+
+	// Emitter stuff
+
+	canonical   bool         // If the output is in the canonical style?
+	best_indent int          // The number of indentation spaces.
+	best_width  int          // The preferred width of the output lines.
+	unicode     bool         // Allow unescaped non-ASCII characters?
+	line_break  yaml_break_t // The preferred line break.
+
+	state  yaml_emitter_state_t   // The current emitter state.
+	states []yaml_emitter_state_t // The stack of states.
+
+	events      []yaml_event_t // The event queue.
+	events_head int            // The head of the event queue.
+
+	indents []int // The stack of indentation levels.
+
+	tag_directives []yaml_tag_directive_t // The list of tag directives.
+
+	indent int // The current indentation level.
+
+	flow_level int // The current flow level.
+
+	root_context       bool // Is it the document root context?
+	sequence_context   bool // Is it a sequence context?
+	mapping_context    bool // Is it a mapping context?
+	simple_key_context bool // Is it a simple mapping key context?
+
+	line       int  // The current line.
+	column     int  // The current column.
+	whitespace bool // If the last character was a whitespace?
+	indention  bool // If the last character was an indentation character (' ', '-', '?', ':')?
+	open_ended bool // If an explicit document end is required?
+
+	// Anchor analysis.
+	anchor_data struct {
+		anchor []byte // The anchor value.
+		alias  bool   // Is it an alias?
+	}
+
+	// Tag analysis.
+	tag_data struct {
+		handle []byte // The tag handle.
+		suffix []byte // The tag suffix.
+	}
+
+	// Scalar analysis.
+	scalar_data struct {
+		value                 []byte              // The scalar value.
+		multiline             bool                // Does the scalar contain line breaks?
+		flow_plain_allowed    bool                // Can the scalar be expessed in the flow plain style?
+		block_plain_allowed   bool                // Can the scalar be expressed in the block plain style?
+		single_quoted_allowed bool                // Can the scalar be expressed in the single quoted style?
+		block_allowed         bool                // Can the scalar be expressed in the literal or folded styles?
+		style                 yaml_scalar_style_t // The output style.
+	}
+
+	// Dumper stuff
+
+	opened bool // If the stream was already opened?
+	closed bool // If the stream was already closed?
+
+	// The information associated with the document nodes.
+	anchors *struct {
+		references int  // The number of references.
+		anchor     int  // The anchor id.
+		serialized bool // If the node has been emitted?
+	}
+
+	last_anchor_id int // The last assigned anchor id.
+
+	document *yaml_document_t // The currently emitted document.
+}

+ 173 - 0
vendor/gopkg.in/yaml.v2/yamlprivateh.go

@@ -0,0 +1,173 @@
+package yaml
+
+const (
+	// The size of the input raw buffer.
+	input_raw_buffer_size = 512
+
+	// The size of the input buffer.
+	// It should be possible to decode the whole raw buffer.
+	input_buffer_size = input_raw_buffer_size * 3
+
+	// The size of the output buffer.
+	output_buffer_size = 128
+
+	// The size of the output raw buffer.
+	// It should be possible to encode the whole output buffer.
+	output_raw_buffer_size = (output_buffer_size*2 + 2)
+
+	// The size of other stacks and queues.
+	initial_stack_size  = 16
+	initial_queue_size  = 16
+	initial_string_size = 16
+)
+
+// Check if the character at the specified position is an alphabetical
+// character, a digit, '_', or '-'.
+func is_alpha(b []byte, i int) bool {
+	return b[i] >= '0' && b[i] <= '9' || b[i] >= 'A' && b[i] <= 'Z' || b[i] >= 'a' && b[i] <= 'z' || b[i] == '_' || b[i] == '-'
+}
+
+// Check if the character at the specified position is a digit.
+func is_digit(b []byte, i int) bool {
+	return b[i] >= '0' && b[i] <= '9'
+}
+
+// Get the value of a digit.
+func as_digit(b []byte, i int) int {
+	return int(b[i]) - '0'
+}
+
+// Check if the character at the specified position is a hex-digit.
+func is_hex(b []byte, i int) bool {
+	return b[i] >= '0' && b[i] <= '9' || b[i] >= 'A' && b[i] <= 'F' || b[i] >= 'a' && b[i] <= 'f'
+}
+
+// Get the value of a hex-digit.
+func as_hex(b []byte, i int) int {
+	bi := b[i]
+	if bi >= 'A' && bi <= 'F' {
+		return int(bi) - 'A' + 10
+	}
+	if bi >= 'a' && bi <= 'f' {
+		return int(bi) - 'a' + 10
+	}
+	return int(bi) - '0'
+}
+
+// Check if the character is ASCII.
+func is_ascii(b []byte, i int) bool {
+	return b[i] <= 0x7F
+}
+
+// Check if the character at the start of the buffer can be printed unescaped.
+func is_printable(b []byte, i int) bool {
+	return ((b[i] == 0x0A) || // . == #x0A
+		(b[i] >= 0x20 && b[i] <= 0x7E) || // #x20 <= . <= #x7E
+		(b[i] == 0xC2 && b[i+1] >= 0xA0) || // #0xA0 <= . <= #xD7FF
+		(b[i] > 0xC2 && b[i] < 0xED) ||
+		(b[i] == 0xED && b[i+1] < 0xA0) ||
+		(b[i] == 0xEE) ||
+		(b[i] == 0xEF && // #xE000 <= . <= #xFFFD
+			!(b[i+1] == 0xBB && b[i+2] == 0xBF) && // && . != #xFEFF
+			!(b[i+1] == 0xBF && (b[i+2] == 0xBE || b[i+2] == 0xBF))))
+}
+
+// Check if the character at the specified position is NUL.
+func is_z(b []byte, i int) bool {
+	return b[i] == 0x00
+}
+
+// Check if the beginning of the buffer is a BOM.
+func is_bom(b []byte, i int) bool {
+	return b[0] == 0xEF && b[1] == 0xBB && b[2] == 0xBF
+}
+
+// Check if the character at the specified position is space.
+func is_space(b []byte, i int) bool {
+	return b[i] == ' '
+}
+
+// Check if the character at the specified position is tab.
+func is_tab(b []byte, i int) bool {
+	return b[i] == '\t'
+}
+
+// Check if the character at the specified position is blank (space or tab).
+func is_blank(b []byte, i int) bool {
+	//return is_space(b, i) || is_tab(b, i)
+	return b[i] == ' ' || b[i] == '\t'
+}
+
+// Check if the character at the specified position is a line break.
+func is_break(b []byte, i int) bool {
+	return (b[i] == '\r' || // CR (#xD)
+		b[i] == '\n' || // LF (#xA)
+		b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85)
+		b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028)
+		b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9) // PS (#x2029)
+}
+
+func is_crlf(b []byte, i int) bool {
+	return b[i] == '\r' && b[i+1] == '\n'
+}
+
+// Check if the character is a line break or NUL.
+func is_breakz(b []byte, i int) bool {
+	//return is_break(b, i) || is_z(b, i)
+	return (        // is_break:
+	b[i] == '\r' || // CR (#xD)
+		b[i] == '\n' || // LF (#xA)
+		b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85)
+		b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028)
+		b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029)
+		// is_z:
+		b[i] == 0)
+}
+
+// Check if the character is a line break, space, or NUL.
+func is_spacez(b []byte, i int) bool {
+	//return is_space(b, i) || is_breakz(b, i)
+	return ( // is_space:
+	b[i] == ' ' ||
+		// is_breakz:
+		b[i] == '\r' || // CR (#xD)
+		b[i] == '\n' || // LF (#xA)
+		b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85)
+		b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028)
+		b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029)
+		b[i] == 0)
+}
+
+// Check if the character is a line break, space, tab, or NUL.
+func is_blankz(b []byte, i int) bool {
+	//return is_blank(b, i) || is_breakz(b, i)
+	return ( // is_blank:
+	b[i] == ' ' || b[i] == '\t' ||
+		// is_breakz:
+		b[i] == '\r' || // CR (#xD)
+		b[i] == '\n' || // LF (#xA)
+		b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85)
+		b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028)
+		b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029)
+		b[i] == 0)
+}
+
+// Determine the width of the character.
+func width(b byte) int {
+	// Don't replace these by a switch without first
+	// confirming that it is being inlined.
+	if b&0x80 == 0x00 {
+		return 1
+	}
+	if b&0xE0 == 0xC0 {
+		return 2
+	}
+	if b&0xF0 == 0xE0 {
+		return 3
+	}
+	if b&0xF8 == 0xF0 {
+		return 4
+	}
+	return 0
+
+}