Browse Source

initial commit

Tanveer Hassan 6 years ago
commit
2bbc92de4a
100 changed files with 10450 additions and 0 deletions
  1. 96 0
      Gopkg.lock
  2. 38 0
      Gopkg.toml
  3. 11 0
      README.md
  4. 53 0
      handler.go
  5. 24 0
      main.go
  6. 25 0
      middleware.go
  7. 4 0
      vendor/github.com/dgrijalva/jwt-go/.gitignore
  8. 13 0
      vendor/github.com/dgrijalva/jwt-go/.travis.yml
  9. 8 0
      vendor/github.com/dgrijalva/jwt-go/LICENSE
  10. 97 0
      vendor/github.com/dgrijalva/jwt-go/MIGRATION_GUIDE.md
  11. 100 0
      vendor/github.com/dgrijalva/jwt-go/README.md
  12. 118 0
      vendor/github.com/dgrijalva/jwt-go/VERSION_HISTORY.md
  13. 134 0
      vendor/github.com/dgrijalva/jwt-go/claims.go
  14. 4 0
      vendor/github.com/dgrijalva/jwt-go/doc.go
  15. 148 0
      vendor/github.com/dgrijalva/jwt-go/ecdsa.go
  16. 67 0
      vendor/github.com/dgrijalva/jwt-go/ecdsa_utils.go
  17. 59 0
      vendor/github.com/dgrijalva/jwt-go/errors.go
  18. 95 0
      vendor/github.com/dgrijalva/jwt-go/hmac.go
  19. 94 0
      vendor/github.com/dgrijalva/jwt-go/map_claims.go
  20. 52 0
      vendor/github.com/dgrijalva/jwt-go/none.go
  21. 148 0
      vendor/github.com/dgrijalva/jwt-go/parser.go
  22. 101 0
      vendor/github.com/dgrijalva/jwt-go/rsa.go
  23. 126 0
      vendor/github.com/dgrijalva/jwt-go/rsa_pss.go
  24. 101 0
      vendor/github.com/dgrijalva/jwt-go/rsa_utils.go
  25. 35 0
      vendor/github.com/dgrijalva/jwt-go/signing_method.go
  26. 108 0
      vendor/github.com/dgrijalva/jwt-go/token.go
  27. 25 0
      vendor/github.com/labstack/echo/.editorconfig
  28. 20 0
      vendor/github.com/labstack/echo/.gitattributes
  29. 7 0
      vendor/github.com/labstack/echo/.gitignore
  30. 15 0
      vendor/github.com/labstack/echo/.travis.yml
  31. 114 0
      vendor/github.com/labstack/echo/Gopkg.lock
  32. 50 0
      vendor/github.com/labstack/echo/Gopkg.toml
  33. 21 0
      vendor/github.com/labstack/echo/LICENSE
  34. 17 0
      vendor/github.com/labstack/echo/Makefile
  35. 99 0
      vendor/github.com/labstack/echo/README.md
  36. 273 0
      vendor/github.com/labstack/echo/bind.go
  37. 576 0
      vendor/github.com/labstack/echo/context.go
  38. 770 0
      vendor/github.com/labstack/echo/echo.go
  39. 15 0
      vendor/github.com/labstack/echo/go.mod
  40. 22 0
      vendor/github.com/labstack/echo/go.sum
  41. 120 0
      vendor/github.com/labstack/echo/group.go
  42. 40 0
      vendor/github.com/labstack/echo/log.go
  43. 106 0
      vendor/github.com/labstack/echo/middleware/basic_auth.go
  44. 111 0
      vendor/github.com/labstack/echo/middleware/body_dump.go
  45. 117 0
      vendor/github.com/labstack/echo/middleware/body_limit.go
  46. 122 0
      vendor/github.com/labstack/echo/middleware/compress.go
  47. 143 0
      vendor/github.com/labstack/echo/middleware/cors.go
  48. 210 0
      vendor/github.com/labstack/echo/middleware/csrf.go
  49. 227 0
      vendor/github.com/labstack/echo/middleware/jwt.go
  50. 150 0
      vendor/github.com/labstack/echo/middleware/key_auth.go
  51. 217 0
      vendor/github.com/labstack/echo/middleware/logger.go
  52. 88 0
      vendor/github.com/labstack/echo/middleware/method_override.go
  53. 38 0
      vendor/github.com/labstack/echo/middleware/middleware.go
  54. 252 0
      vendor/github.com/labstack/echo/middleware/proxy.go
  55. 81 0
      vendor/github.com/labstack/echo/middleware/recover.go
  56. 153 0
      vendor/github.com/labstack/echo/middleware/redirect.go
  57. 64 0
      vendor/github.com/labstack/echo/middleware/request_id.go
  58. 84 0
      vendor/github.com/labstack/echo/middleware/rewrite.go
  59. 116 0
      vendor/github.com/labstack/echo/middleware/secure.go
  60. 119 0
      vendor/github.com/labstack/echo/middleware/slash.go
  61. 229 0
      vendor/github.com/labstack/echo/middleware/static.go
  62. 110 0
      vendor/github.com/labstack/echo/response.go
  63. 434 0
      vendor/github.com/labstack/echo/router.go
  64. 22 0
      vendor/github.com/labstack/gommon/LICENSE
  65. 29 0
      vendor/github.com/labstack/gommon/bytes/README.md
  66. 108 0
      vendor/github.com/labstack/gommon/bytes/bytes.go
  67. 86 0
      vendor/github.com/labstack/gommon/color/README.md
  68. 407 0
      vendor/github.com/labstack/gommon/color/color.go
  69. 5 0
      vendor/github.com/labstack/gommon/log/README.md
  70. 13 0
      vendor/github.com/labstack/gommon/log/color.go
  71. 415 0
      vendor/github.com/labstack/gommon/log/log.go
  72. 12 0
      vendor/github.com/labstack/gommon/log/white.go
  73. 48 0
      vendor/github.com/labstack/gommon/random/random.go
  74. 9 0
      vendor/github.com/mattn/go-colorable/.travis.yml
  75. 21 0
      vendor/github.com/mattn/go-colorable/LICENSE
  76. 48 0
      vendor/github.com/mattn/go-colorable/README.md
  77. 29 0
      vendor/github.com/mattn/go-colorable/colorable_appengine.go
  78. 30 0
      vendor/github.com/mattn/go-colorable/colorable_others.go
  79. 884 0
      vendor/github.com/mattn/go-colorable/colorable_windows.go
  80. 55 0
      vendor/github.com/mattn/go-colorable/noncolorable.go
  81. 13 0
      vendor/github.com/mattn/go-isatty/.travis.yml
  82. 9 0
      vendor/github.com/mattn/go-isatty/LICENSE
  83. 50 0
      vendor/github.com/mattn/go-isatty/README.md
  84. 2 0
      vendor/github.com/mattn/go-isatty/doc.go
  85. 15 0
      vendor/github.com/mattn/go-isatty/isatty_appengine.go
  86. 18 0
      vendor/github.com/mattn/go-isatty/isatty_bsd.go
  87. 18 0
      vendor/github.com/mattn/go-isatty/isatty_linux.go
  88. 19 0
      vendor/github.com/mattn/go-isatty/isatty_linux_ppc64x.go
  89. 10 0
      vendor/github.com/mattn/go-isatty/isatty_others.go
  90. 16 0
      vendor/github.com/mattn/go-isatty/isatty_solaris.go
  91. 94 0
      vendor/github.com/mattn/go-isatty/isatty_windows.go
  92. 15 0
      vendor/github.com/valyala/bytebufferpool/.travis.yml
  93. 22 0
      vendor/github.com/valyala/bytebufferpool/LICENSE
  94. 21 0
      vendor/github.com/valyala/bytebufferpool/README.md
  95. 111 0
      vendor/github.com/valyala/bytebufferpool/bytebuffer.go
  96. 7 0
      vendor/github.com/valyala/bytebufferpool/doc.go
  97. 151 0
      vendor/github.com/valyala/bytebufferpool/pool.go
  98. 22 0
      vendor/github.com/valyala/fasttemplate/LICENSE
  99. 85 0
      vendor/github.com/valyala/fasttemplate/README.md
  100. 317 0
      vendor/github.com/valyala/fasttemplate/template.go

+ 96 - 0
Gopkg.lock

@@ -0,0 +1,96 @@
+# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
+
+
+[[projects]]
+  digest = "1:76dc72490af7174349349838f2fe118996381b31ea83243812a97e5a0fd5ed55"
+  name = "github.com/dgrijalva/jwt-go"
+  packages = ["."]
+  pruneopts = "UT"
+  revision = "06ea1031745cb8b3dab3f6a236daf2b0aa468b7e"
+  version = "v3.2.0"
+
+[[projects]]
+  digest = "1:9acadb9c8c15b8a9f635a7fa960c9a522b001a3919bc03df92ac26c372476aff"
+  name = "github.com/labstack/echo"
+  packages = [
+    ".",
+    "middleware",
+  ]
+  pruneopts = "UT"
+  revision = "1abaa3049251d17932e4313c2d6165073fd07fd8"
+  version = "v3.3.6"
+
+[[projects]]
+  digest = "1:568171fc14a3d819b112c3e219d351ea7b05e8dad7935c4168c6b3373244a686"
+  name = "github.com/labstack/gommon"
+  packages = [
+    "bytes",
+    "color",
+    "log",
+    "random",
+  ]
+  pruneopts = "UT"
+  revision = "2a618302b929cc20862dda3aa6f02f64dbe740dd"
+  version = "v0.2.7"
+
+[[projects]]
+  digest = "1:c658e84ad3916da105a761660dcaeb01e63416c8ec7bc62256a9b411a05fcd67"
+  name = "github.com/mattn/go-colorable"
+  packages = ["."]
+  pruneopts = "UT"
+  revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072"
+  version = "v0.0.9"
+
+[[projects]]
+  digest = "1:0981502f9816113c9c8c4ac301583841855c8cf4da8c72f696b3ebedf6d0e4e5"
+  name = "github.com/mattn/go-isatty"
+  packages = ["."]
+  pruneopts = "UT"
+  revision = "6ca4dbf54d38eea1a992b3c722a76a5d1c4cb25c"
+  version = "v0.0.4"
+
+[[projects]]
+  digest = "1:c468422f334a6b46a19448ad59aaffdfc0a36b08fdcc1c749a0b29b6453d7e59"
+  name = "github.com/valyala/bytebufferpool"
+  packages = ["."]
+  pruneopts = "UT"
+  revision = "e746df99fe4a3986f4d4f79e13c1e0117ce9c2f7"
+  version = "v1.0.0"
+
+[[projects]]
+  branch = "master"
+  digest = "1:268b8bce0064e8c057d7b913605459f9a26dcab864c0886a56d196540fbf003f"
+  name = "github.com/valyala/fasttemplate"
+  packages = ["."]
+  pruneopts = "UT"
+  revision = "dcecefd839c4193db0d35b88ec65b4c12d360ab0"
+
+[[projects]]
+  branch = "master"
+  digest = "1:674a2405f77863f4f362e3e45078fd9caa647dc1c0e8b022e3b9dc1ae89fbc8f"
+  name = "golang.org/x/crypto"
+  packages = [
+    "acme",
+    "acme/autocert",
+  ]
+  pruneopts = "UT"
+  revision = "45a5f77698d342a8c2ef8423abdf0ba6880b008a"
+
+[[projects]]
+  branch = "master"
+  digest = "1:f22e437d9328275884d0ae018ed0de4c280871c944a5ab332aa37fd71fb5801b"
+  name = "golang.org/x/sys"
+  packages = ["unix"]
+  pruneopts = "UT"
+  revision = "95b1ffbd15a57cc5abb3f04402b9e8ec0016a52c"
+
+[solve-meta]
+  analyzer-name = "dep"
+  analyzer-version = 1
+  input-imports = [
+    "github.com/dgrijalva/jwt-go",
+    "github.com/labstack/echo",
+    "github.com/labstack/echo/middleware",
+  ]
+  solver-name = "gps-cdcl"
+  solver-version = 1

+ 38 - 0
Gopkg.toml

@@ -0,0 +1,38 @@
+# Gopkg.toml example
+#
+# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html
+# for detailed Gopkg.toml documentation.
+#
+# required = ["github.com/user/thing/cmd/thing"]
+# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
+#
+# [[constraint]]
+#   name = "github.com/user/project"
+#   version = "1.0.0"
+#
+# [[constraint]]
+#   name = "github.com/user/project2"
+#   branch = "dev"
+#   source = "github.com/myfork/project2"
+#
+# [[override]]
+#   name = "github.com/x/y"
+#   version = "2.4.0"
+#
+# [prune]
+#   non-go = false
+#   go-tests = true
+#   unused-packages = true
+
+
+[prune]
+  go-tests = true
+  unused-packages = true
+
+[[constraint]]
+  name = "github.com/dgrijalva/jwt-go"
+  version = "3.2.0"
+
+[[constraint]]
+  name = "github.com/labstack/echo"
+  version = "3.3.6"

+ 11 - 0
README.md

@@ -0,0 +1,11 @@
+# JWT Authentication in Golang
+
+A basic Golang application showing how to implement JWT authentication using the Echo framework.
+
+## How to run
+
+`go run *.go`
+
+## Contributions
+
+If you find any improvement scopes, please free to contribute.

+ 53 - 0
handler.go

@@ -0,0 +1,53 @@
+package main
+
+import (
+	"net/http"
+	"time"
+
+	"github.com/dgrijalva/jwt-go"
+	"github.com/labstack/echo"
+)
+
+type handler struct{}
+
+// Most of the code is taken from the echo guide
+// https://echo.labstack.com/cookbook/jwt
+func (h *handler) login(c echo.Context) error {
+	username := c.FormValue("username")
+	password := c.FormValue("password")
+
+	// Check in your db if the user exists or not
+	if username == "jon" && password == "password" {
+		// Create token
+		token := jwt.New(jwt.SigningMethodHS256)
+
+		// Set claims
+		// This is the information which frontend can use
+		// The backend can also decode the token and get admin etc.
+		claims := token.Claims.(jwt.MapClaims)
+		claims["name"] = "Jon Doe"
+		claims["admin"] = true
+		claims["exp"] = time.Now().Add(time.Hour * 72).Unix()
+
+		// Generate encoded token and send it as response.
+		// The signing string should be secret (a generated UUID works too)
+		t, err := token.SignedString([]byte("secret"))
+		if err != nil {
+			return err
+		}
+		return c.JSON(http.StatusOK, map[string]string{
+			"token": t,
+		})
+	}
+
+	return echo.ErrUnauthorized
+}
+
+// Most of the code is taken from the echo guide
+// https://echo.labstack.com/cookbook/jwt
+func (h *handler) private(c echo.Context) error {
+	user := c.Get("user").(*jwt.Token)
+	claims := user.Claims.(jwt.MapClaims)
+	name := claims["name"].(string)
+	return c.String(http.StatusOK, "Welcome "+name+"!")
+}

+ 24 - 0
main.go

@@ -0,0 +1,24 @@
+package main
+
+import (
+	"net/http"
+
+	"github.com/labstack/echo"
+)
+
+func main() {
+	e := echo.New()
+	e.GET("/", func(c echo.Context) error {
+		return c.String(http.StatusOK, "Hello, World!")
+	})
+
+	h := &handler{}
+
+	e.POST("/login", h.login)
+
+	e.GET("/private", h.private, isLoggedIn)
+
+	e.GET("/admin", h.private, isLoggedIn, isAdmin)
+
+	e.Logger.Fatal(e.Start(":1323"))
+}

+ 25 - 0
middleware.go

@@ -0,0 +1,25 @@
+package main
+
+import (
+	"github.com/dgrijalva/jwt-go"
+	"github.com/labstack/echo"
+	"github.com/labstack/echo/middleware"
+)
+
+var isLoggedIn = middleware.JWTWithConfig(middleware.JWTConfig{
+	SigningKey: []byte("secret"),
+})
+
+func isAdmin(next echo.HandlerFunc) echo.HandlerFunc {
+	return func(c echo.Context) error {
+		user := c.Get("user").(*jwt.Token)
+		claims := user.Claims.(jwt.MapClaims)
+		isAdmin := claims["admin"].(bool)
+
+		if isAdmin == false {
+			return echo.ErrUnauthorized
+		}
+
+		return next(c)
+	}
+}

+ 4 - 0
vendor/github.com/dgrijalva/jwt-go/.gitignore

@@ -0,0 +1,4 @@
+.DS_Store
+bin
+
+

+ 13 - 0
vendor/github.com/dgrijalva/jwt-go/.travis.yml

@@ -0,0 +1,13 @@
+language: go
+
+script:
+    - go vet ./...
+    - go test -v ./...
+
+go:
+  - 1.3
+  - 1.4
+  - 1.5
+  - 1.6
+  - 1.7
+  - tip

+ 8 - 0
vendor/github.com/dgrijalva/jwt-go/LICENSE

@@ -0,0 +1,8 @@
+Copyright (c) 2012 Dave Grijalva
+
+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.
+

+ 97 - 0
vendor/github.com/dgrijalva/jwt-go/MIGRATION_GUIDE.md

@@ -0,0 +1,97 @@
+## Migration Guide from v2 -> v3
+
+Version 3 adds several new, frequently requested features.  To do so, it introduces a few breaking changes.  We've worked to keep these as minimal as possible.  This guide explains the breaking changes and how you can quickly update your code.
+
+### `Token.Claims` is now an interface type
+
+The most requested feature from the 2.0 verison of this library was the ability to provide a custom type to the JSON parser for claims. This was implemented by introducing a new interface, `Claims`, to replace `map[string]interface{}`.  We also included two concrete implementations of `Claims`: `MapClaims` and `StandardClaims`.
+
+`MapClaims` is an alias for `map[string]interface{}` with built in validation behavior.  It is the default claims type when using `Parse`.  The usage is unchanged except you must type cast the claims property.
+
+The old example for parsing a token looked like this..
+
+```go
+	if token, err := jwt.Parse(tokenString, keyLookupFunc); err == nil {
+		fmt.Printf("Token for user %v expires %v", token.Claims["user"], token.Claims["exp"])
+	}
+```
+
+is now directly mapped to...
+
+```go
+	if token, err := jwt.Parse(tokenString, keyLookupFunc); err == nil {
+		claims := token.Claims.(jwt.MapClaims)
+		fmt.Printf("Token for user %v expires %v", claims["user"], claims["exp"])
+	}
+```
+
+`StandardClaims` is designed to be embedded in your custom type.  You can supply a custom claims type with the new `ParseWithClaims` function.  Here's an example of using a custom claims type.
+
+```go
+	type MyCustomClaims struct {
+		User string
+		*StandardClaims
+	}
+	
+	if token, err := jwt.ParseWithClaims(tokenString, &MyCustomClaims{}, keyLookupFunc); err == nil {
+		claims := token.Claims.(*MyCustomClaims)
+		fmt.Printf("Token for user %v expires %v", claims.User, claims.StandardClaims.ExpiresAt)
+	}
+```
+
+### `ParseFromRequest` has been moved
+
+To keep this library focused on the tokens without becoming overburdened with complex request processing logic, `ParseFromRequest` and its new companion `ParseFromRequestWithClaims` have been moved to a subpackage, `request`.  The method signatues have also been augmented to receive a new argument: `Extractor`.
+
+`Extractors` do the work of picking the token string out of a request.  The interface is simple and composable.
+
+This simple parsing example:
+
+```go
+	if token, err := jwt.ParseFromRequest(tokenString, req, keyLookupFunc); err == nil {
+		fmt.Printf("Token for user %v expires %v", token.Claims["user"], token.Claims["exp"])
+	}
+```
+
+is directly mapped to:
+
+```go
+	if token, err := request.ParseFromRequest(req, request.OAuth2Extractor, keyLookupFunc); err == nil {
+		claims := token.Claims.(jwt.MapClaims)
+		fmt.Printf("Token for user %v expires %v", claims["user"], claims["exp"])
+	}
+```
+
+There are several concrete `Extractor` types provided for your convenience:
+
+* `HeaderExtractor` will search a list of headers until one contains content.
+* `ArgumentExtractor` will search a list of keys in request query and form arguments until one contains content.
+* `MultiExtractor` will try a list of `Extractors` in order until one returns content.
+* `AuthorizationHeaderExtractor` will look in the `Authorization` header for a `Bearer` token.
+* `OAuth2Extractor` searches the places an OAuth2 token would be specified (per the spec): `Authorization` header and `access_token` argument
+* `PostExtractionFilter` wraps an `Extractor`, allowing you to process the content before it's parsed.  A simple example is stripping the `Bearer ` text from a header
+
+
+### RSA signing methods no longer accept `[]byte` keys
+
+Due to a [critical vulnerability](https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/), we've decided the convenience of accepting `[]byte` instead of `rsa.PublicKey` or `rsa.PrivateKey` isn't worth the risk of misuse.
+
+To replace this behavior, we've added two helper methods: `ParseRSAPrivateKeyFromPEM(key []byte) (*rsa.PrivateKey, error)` and `ParseRSAPublicKeyFromPEM(key []byte) (*rsa.PublicKey, error)`.  These are just simple helpers for unpacking PEM encoded PKCS1 and PKCS8 keys. If your keys are encoded any other way, all you need to do is convert them to the `crypto/rsa` package's types.
+
+```go 
+	func keyLookupFunc(*Token) (interface{}, error) {
+		// Don't forget to validate the alg is what you expect:
+		if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
+			return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
+		}
+		
+		// Look up key 
+		key, err := lookupPublicKey(token.Header["kid"])
+		if err != nil {
+			return nil, err
+		}
+		
+		// Unpack key from PEM encoded PKCS8
+		return jwt.ParseRSAPublicKeyFromPEM(key)
+	}
+```

+ 100 - 0
vendor/github.com/dgrijalva/jwt-go/README.md

@@ -0,0 +1,100 @@
+# jwt-go
+
+[![Build Status](https://travis-ci.org/dgrijalva/jwt-go.svg?branch=master)](https://travis-ci.org/dgrijalva/jwt-go)
+[![GoDoc](https://godoc.org/github.com/dgrijalva/jwt-go?status.svg)](https://godoc.org/github.com/dgrijalva/jwt-go)
+
+A [go](http://www.golang.org) (or 'golang' for search engine friendliness) implementation of [JSON Web Tokens](http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html)
+
+**NEW VERSION COMING:** There have been a lot of improvements suggested since the version 3.0.0 released in 2016. I'm working now on cutting two different releases: 3.2.0 will contain any non-breaking changes or enhancements. 4.0.0 will follow shortly which will include breaking changes. See the 4.0.0 milestone to get an idea of what's coming. If you have other ideas, or would like to participate in 4.0.0, now's the time. If you depend on this library and don't want to be interrupted, I recommend you use your dependency mangement tool to pin to version 3. 
+
+**SECURITY NOTICE:** Some older versions of Go have a security issue in the cryotp/elliptic. Recommendation is to upgrade to at least 1.8.3. See issue #216 for more detail.
+
+**SECURITY NOTICE:** It's important that you [validate the `alg` presented is what you expect](https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/). This library attempts to make it easy to do the right thing by requiring key types match the expected alg, but you should take the extra step to verify it in your usage.  See the examples provided.
+
+## What the heck is a JWT?
+
+JWT.io has [a great introduction](https://jwt.io/introduction) to JSON Web Tokens.
+
+In short, it's a signed JSON object that does something useful (for example, authentication).  It's commonly used for `Bearer` tokens in Oauth 2.  A token is made of three parts, separated by `.`'s.  The first two parts are JSON objects, that have been [base64url](http://tools.ietf.org/html/rfc4648) encoded.  The last part is the signature, encoded the same way.
+
+The first part is called the header.  It contains the necessary information for verifying the last part, the signature.  For example, which encryption method was used for signing and what key was used.
+
+The part in the middle is the interesting bit.  It's called the Claims and contains the actual stuff you care about.  Refer to [the RFC](http://self-issued.info/docs/draft-jones-json-web-token.html) for information about reserved keys and the proper way to add your own.
+
+## What's in the box?
+
+This library supports the parsing and verification as well as the generation and signing of JWTs.  Current supported signing algorithms are HMAC SHA, RSA, RSA-PSS, and ECDSA, though hooks are present for adding your own.
+
+## Examples
+
+See [the project documentation](https://godoc.org/github.com/dgrijalva/jwt-go) for examples of usage:
+
+* [Simple example of parsing and validating a token](https://godoc.org/github.com/dgrijalva/jwt-go#example-Parse--Hmac)
+* [Simple example of building and signing a token](https://godoc.org/github.com/dgrijalva/jwt-go#example-New--Hmac)
+* [Directory of Examples](https://godoc.org/github.com/dgrijalva/jwt-go#pkg-examples)
+
+## Extensions
+
+This library publishes all the necessary components for adding your own signing methods.  Simply implement the `SigningMethod` interface and register a factory method using `RegisterSigningMethod`.  
+
+Here's an example of an extension that integrates with the Google App Engine signing tools: https://github.com/someone1/gcp-jwt-go
+
+## Compliance
+
+This library was last reviewed to comply with [RTF 7519](http://www.rfc-editor.org/info/rfc7519) dated May 2015 with a few notable differences:
+
+* In order to protect against accidental use of [Unsecured JWTs](http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html#UnsecuredJWT), tokens using `alg=none` will only be accepted if the constant `jwt.UnsafeAllowNoneSignatureType` is provided as the key.
+
+## Project Status & Versioning
+
+This library is considered production ready.  Feedback and feature requests are appreciated.  The API should be considered stable.  There should be very few backwards-incompatible changes outside of major version updates (and only with good reason).
+
+This project uses [Semantic Versioning 2.0.0](http://semver.org).  Accepted pull requests will land on `master`.  Periodically, versions will be tagged from `master`.  You can find all the releases on [the project releases page](https://github.com/dgrijalva/jwt-go/releases).
+
+While we try to make it obvious when we make breaking changes, there isn't a great mechanism for pushing announcements out to users.  You may want to use this alternative package include: `gopkg.in/dgrijalva/jwt-go.v3`.  It will do the right thing WRT semantic versioning.
+
+**BREAKING CHANGES:*** 
+* Version 3.0.0 includes _a lot_ of changes from the 2.x line, including a few that break the API.  We've tried to break as few things as possible, so there should just be a few type signature changes.  A full list of breaking changes is available in `VERSION_HISTORY.md`.  See `MIGRATION_GUIDE.md` for more information on updating your code.
+
+## Usage Tips
+
+### Signing vs Encryption
+
+A token is simply a JSON object that is signed by its author. this tells you exactly two things about the data:
+
+* The author of the token was in the possession of the signing secret
+* The data has not been modified since it was signed
+
+It's important to know that JWT does not provide encryption, which means anyone who has access to the token can read its contents. If you need to protect (encrypt) the data, there is a companion spec, `JWE`, that provides this functionality. JWE is currently outside the scope of this library.
+
+### Choosing a Signing Method
+
+There are several signing methods available, and you should probably take the time to learn about the various options before choosing one.  The principal design decision is most likely going to be symmetric vs asymmetric.
+
+Symmetric signing methods, such as HSA, use only a single secret. This is probably the simplest signing method to use since any `[]byte` can be used as a valid secret. They are also slightly computationally faster to use, though this rarely is enough to matter. Symmetric signing methods work the best when both producers and consumers of tokens are trusted, or even the same system. Since the same secret is used to both sign and validate tokens, you can't easily distribute the key for validation.
+
+Asymmetric signing methods, such as RSA, use different keys for signing and verifying tokens. This makes it possible to produce tokens with a private key, and allow any consumer to access the public key for verification.
+
+### Signing Methods and Key Types
+
+Each signing method expects a different object type for its signing keys. See the package documentation for details. Here are the most common ones:
+
+* The [HMAC signing method](https://godoc.org/github.com/dgrijalva/jwt-go#SigningMethodHMAC) (`HS256`,`HS384`,`HS512`) expect `[]byte` values for signing and validation
+* The [RSA signing method](https://godoc.org/github.com/dgrijalva/jwt-go#SigningMethodRSA) (`RS256`,`RS384`,`RS512`) expect `*rsa.PrivateKey` for signing and `*rsa.PublicKey` for validation
+* The [ECDSA signing method](https://godoc.org/github.com/dgrijalva/jwt-go#SigningMethodECDSA) (`ES256`,`ES384`,`ES512`) expect `*ecdsa.PrivateKey` for signing and `*ecdsa.PublicKey` for validation
+
+### JWT and OAuth
+
+It's worth mentioning that OAuth and JWT are not the same thing. A JWT token is simply a signed JSON object. It can be used anywhere such a thing is useful. There is some confusion, though, as JWT is the most common type of bearer token used in OAuth2 authentication.
+
+Without going too far down the rabbit hole, here's a description of the interaction of these technologies:
+
+* OAuth is a protocol for allowing an identity provider to be separate from the service a user is logging in to. For example, whenever you use Facebook to log into a different service (Yelp, Spotify, etc), you are using OAuth.
+* OAuth defines several options for passing around authentication data. One popular method is called a "bearer token". A bearer token is simply a string that _should_ only be held by an authenticated user. Thus, simply presenting this token proves your identity. You can probably derive from here why a JWT might make a good bearer token.
+* Because bearer tokens are used for authentication, it's important they're kept secret. This is why transactions that use bearer tokens typically happen over SSL.
+
+## More
+
+Documentation can be found [on godoc.org](http://godoc.org/github.com/dgrijalva/jwt-go).
+
+The command line utility included in this project (cmd/jwt) provides a straightforward example of token creation and parsing as well as a useful tool for debugging your own integration. You'll also find several implementation examples in the documentation.

+ 118 - 0
vendor/github.com/dgrijalva/jwt-go/VERSION_HISTORY.md

@@ -0,0 +1,118 @@
+## `jwt-go` Version History
+
+#### 3.2.0
+
+* Added method `ParseUnverified` to allow users to split up the tasks of parsing and validation
+* HMAC signing method returns `ErrInvalidKeyType` instead of `ErrInvalidKey` where appropriate
+* Added options to `request.ParseFromRequest`, which allows for an arbitrary list of modifiers to parsing behavior. Initial set include `WithClaims` and `WithParser`. Existing usage of this function will continue to work as before.
+* Deprecated `ParseFromRequestWithClaims` to simplify API in the future.
+
+#### 3.1.0
+
+* Improvements to `jwt` command line tool
+* Added `SkipClaimsValidation` option to `Parser`
+* Documentation updates
+
+#### 3.0.0
+
+* **Compatibility Breaking Changes**: See MIGRATION_GUIDE.md for tips on updating your code
+	* Dropped support for `[]byte` keys when using RSA signing methods.  This convenience feature could contribute to security vulnerabilities involving mismatched key types with signing methods.
+	* `ParseFromRequest` has been moved to `request` subpackage and usage has changed
+	* The `Claims` property on `Token` is now type `Claims` instead of `map[string]interface{}`.  The default value is type `MapClaims`, which is an alias to `map[string]interface{}`.  This makes it possible to use a custom type when decoding claims.
+* Other Additions and Changes
+	* Added `Claims` interface type to allow users to decode the claims into a custom type
+	* Added `ParseWithClaims`, which takes a third argument of type `Claims`.  Use this function instead of `Parse` if you have a custom type you'd like to decode into.
+	* Dramatically improved the functionality and flexibility of `ParseFromRequest`, which is now in the `request` subpackage
+	* Added `ParseFromRequestWithClaims` which is the `FromRequest` equivalent of `ParseWithClaims`
+	* Added new interface type `Extractor`, which is used for extracting JWT strings from http requests.  Used with `ParseFromRequest` and `ParseFromRequestWithClaims`.
+	* Added several new, more specific, validation errors to error type bitmask
+	* Moved examples from README to executable example files
+	* Signing method registry is now thread safe
+	* Added new property to `ValidationError`, which contains the raw error returned by calls made by parse/verify (such as those returned by keyfunc or json parser)
+
+#### 2.7.0
+
+This will likely be the last backwards compatible release before 3.0.0, excluding essential bug fixes.
+
+* Added new option `-show` to the `jwt` command that will just output the decoded token without verifying
+* Error text for expired tokens includes how long it's been expired
+* Fixed incorrect error returned from `ParseRSAPublicKeyFromPEM`
+* Documentation updates
+
+#### 2.6.0
+
+* Exposed inner error within ValidationError
+* Fixed validation errors when using UseJSONNumber flag
+* Added several unit tests
+
+#### 2.5.0
+
+* Added support for signing method none.  You shouldn't use this.  The API tries to make this clear.
+* Updated/fixed some documentation
+* Added more helpful error message when trying to parse tokens that begin with `BEARER `
+
+#### 2.4.0
+
+* Added new type, Parser, to allow for configuration of various parsing parameters
+	* You can now specify a list of valid signing methods.  Anything outside this set will be rejected.
+	* You can now opt to use the `json.Number` type instead of `float64` when parsing token JSON
+* Added support for [Travis CI](https://travis-ci.org/dgrijalva/jwt-go)
+* Fixed some bugs with ECDSA parsing
+
+#### 2.3.0
+
+* Added support for ECDSA signing methods
+* Added support for RSA PSS signing methods (requires go v1.4)
+
+#### 2.2.0
+
+* Gracefully handle a `nil` `Keyfunc` being passed to `Parse`.  Result will now be the parsed token and an error, instead of a panic.
+
+#### 2.1.0
+
+Backwards compatible API change that was missed in 2.0.0.
+
+* The `SignedString` method on `Token` now takes `interface{}` instead of `[]byte`
+
+#### 2.0.0
+
+There were two major reasons for breaking backwards compatibility with this update.  The first was a refactor required to expand the width of the RSA and HMAC-SHA signing implementations.  There will likely be no required code changes to support this change.
+
+The second update, while unfortunately requiring a small change in integration, is required to open up this library to other signing methods.  Not all keys used for all signing methods have a single standard on-disk representation.  Requiring `[]byte` as the type for all keys proved too limiting.  Additionally, this implementation allows for pre-parsed tokens to be reused, which might matter in an application that parses a high volume of tokens with a small set of keys.  Backwards compatibilty has been maintained for passing `[]byte` to the RSA signing methods, but they will also accept `*rsa.PublicKey` and `*rsa.PrivateKey`.
+
+It is likely the only integration change required here will be to change `func(t *jwt.Token) ([]byte, error)` to `func(t *jwt.Token) (interface{}, error)` when calling `Parse`.
+
+* **Compatibility Breaking Changes**
+	* `SigningMethodHS256` is now `*SigningMethodHMAC` instead of `type struct`
+	* `SigningMethodRS256` is now `*SigningMethodRSA` instead of `type struct`
+	* `KeyFunc` now returns `interface{}` instead of `[]byte`
+	* `SigningMethod.Sign` now takes `interface{}` instead of `[]byte` for the key
+	* `SigningMethod.Verify` now takes `interface{}` instead of `[]byte` for the key
+* Renamed type `SigningMethodHS256` to `SigningMethodHMAC`.  Specific sizes are now just instances of this type.
+    * Added public package global `SigningMethodHS256`
+    * Added public package global `SigningMethodHS384`
+    * Added public package global `SigningMethodHS512`
+* Renamed type `SigningMethodRS256` to `SigningMethodRSA`.  Specific sizes are now just instances of this type.
+    * Added public package global `SigningMethodRS256`
+    * Added public package global `SigningMethodRS384`
+    * Added public package global `SigningMethodRS512`
+* Moved sample private key for HMAC tests from an inline value to a file on disk.  Value is unchanged.
+* Refactored the RSA implementation to be easier to read
+* Exposed helper methods `ParseRSAPrivateKeyFromPEM` and `ParseRSAPublicKeyFromPEM`
+
+#### 1.0.2
+
+* Fixed bug in parsing public keys from certificates
+* Added more tests around the parsing of keys for RS256
+* Code refactoring in RS256 implementation.  No functional changes
+
+#### 1.0.1
+
+* Fixed panic if RS256 signing method was passed an invalid key
+
+#### 1.0.0
+
+* First versioned release
+* API stabilized
+* Supports creating, signing, parsing, and validating JWT tokens
+* Supports RS256 and HS256 signing methods

+ 134 - 0
vendor/github.com/dgrijalva/jwt-go/claims.go

@@ -0,0 +1,134 @@
+package jwt
+
+import (
+	"crypto/subtle"
+	"fmt"
+	"time"
+)
+
+// For a type to be a Claims object, it must just have a Valid method that determines
+// if the token is invalid for any supported reason
+type Claims interface {
+	Valid() error
+}
+
+// Structured version of Claims Section, as referenced at
+// https://tools.ietf.org/html/rfc7519#section-4.1
+// See examples for how to use this with your own claim types
+type StandardClaims struct {
+	Audience  string `json:"aud,omitempty"`
+	ExpiresAt int64  `json:"exp,omitempty"`
+	Id        string `json:"jti,omitempty"`
+	IssuedAt  int64  `json:"iat,omitempty"`
+	Issuer    string `json:"iss,omitempty"`
+	NotBefore int64  `json:"nbf,omitempty"`
+	Subject   string `json:"sub,omitempty"`
+}
+
+// Validates time based claims "exp, iat, nbf".
+// There is no accounting for clock skew.
+// As well, if any of the above claims are not in the token, it will still
+// be considered a valid claim.
+func (c StandardClaims) Valid() error {
+	vErr := new(ValidationError)
+	now := TimeFunc().Unix()
+
+	// The claims below are optional, by default, so if they are set to the
+	// default value in Go, let's not fail the verification for them.
+	if c.VerifyExpiresAt(now, false) == false {
+		delta := time.Unix(now, 0).Sub(time.Unix(c.ExpiresAt, 0))
+		vErr.Inner = fmt.Errorf("token is expired by %v", delta)
+		vErr.Errors |= ValidationErrorExpired
+	}
+
+	if c.VerifyIssuedAt(now, false) == false {
+		vErr.Inner = fmt.Errorf("Token used before issued")
+		vErr.Errors |= ValidationErrorIssuedAt
+	}
+
+	if c.VerifyNotBefore(now, false) == false {
+		vErr.Inner = fmt.Errorf("token is not valid yet")
+		vErr.Errors |= ValidationErrorNotValidYet
+	}
+
+	if vErr.valid() {
+		return nil
+	}
+
+	return vErr
+}
+
+// Compares the aud claim against cmp.
+// If required is false, this method will return true if the value matches or is unset
+func (c *StandardClaims) VerifyAudience(cmp string, req bool) bool {
+	return verifyAud(c.Audience, cmp, req)
+}
+
+// Compares the exp claim against cmp.
+// If required is false, this method will return true if the value matches or is unset
+func (c *StandardClaims) VerifyExpiresAt(cmp int64, req bool) bool {
+	return verifyExp(c.ExpiresAt, cmp, req)
+}
+
+// Compares the iat claim against cmp.
+// If required is false, this method will return true if the value matches or is unset
+func (c *StandardClaims) VerifyIssuedAt(cmp int64, req bool) bool {
+	return verifyIat(c.IssuedAt, cmp, req)
+}
+
+// Compares the iss claim against cmp.
+// If required is false, this method will return true if the value matches or is unset
+func (c *StandardClaims) VerifyIssuer(cmp string, req bool) bool {
+	return verifyIss(c.Issuer, cmp, req)
+}
+
+// Compares the nbf claim against cmp.
+// If required is false, this method will return true if the value matches or is unset
+func (c *StandardClaims) VerifyNotBefore(cmp int64, req bool) bool {
+	return verifyNbf(c.NotBefore, cmp, req)
+}
+
+// ----- helpers
+
+func verifyAud(aud string, cmp string, required bool) bool {
+	if aud == "" {
+		return !required
+	}
+	if subtle.ConstantTimeCompare([]byte(aud), []byte(cmp)) != 0 {
+		return true
+	} else {
+		return false
+	}
+}
+
+func verifyExp(exp int64, now int64, required bool) bool {
+	if exp == 0 {
+		return !required
+	}
+	return now <= exp
+}
+
+func verifyIat(iat int64, now int64, required bool) bool {
+	if iat == 0 {
+		return !required
+	}
+	return now >= iat
+}
+
+func verifyIss(iss string, cmp string, required bool) bool {
+	if iss == "" {
+		return !required
+	}
+	if subtle.ConstantTimeCompare([]byte(iss), []byte(cmp)) != 0 {
+		return true
+	} else {
+		return false
+	}
+}
+
+func verifyNbf(nbf int64, now int64, required bool) bool {
+	if nbf == 0 {
+		return !required
+	}
+	return now >= nbf
+}

+ 4 - 0
vendor/github.com/dgrijalva/jwt-go/doc.go

@@ -0,0 +1,4 @@
+// Package jwt is a Go implementation of JSON Web Tokens: http://self-issued.info/docs/draft-jones-json-web-token.html
+//
+// See README.md for more info.
+package jwt

+ 148 - 0
vendor/github.com/dgrijalva/jwt-go/ecdsa.go

@@ -0,0 +1,148 @@
+package jwt
+
+import (
+	"crypto"
+	"crypto/ecdsa"
+	"crypto/rand"
+	"errors"
+	"math/big"
+)
+
+var (
+	// Sadly this is missing from crypto/ecdsa compared to crypto/rsa
+	ErrECDSAVerification = errors.New("crypto/ecdsa: verification error")
+)
+
+// Implements the ECDSA family of signing methods signing methods
+// Expects *ecdsa.PrivateKey for signing and *ecdsa.PublicKey for verification
+type SigningMethodECDSA struct {
+	Name      string
+	Hash      crypto.Hash
+	KeySize   int
+	CurveBits int
+}
+
+// Specific instances for EC256 and company
+var (
+	SigningMethodES256 *SigningMethodECDSA
+	SigningMethodES384 *SigningMethodECDSA
+	SigningMethodES512 *SigningMethodECDSA
+)
+
+func init() {
+	// ES256
+	SigningMethodES256 = &SigningMethodECDSA{"ES256", crypto.SHA256, 32, 256}
+	RegisterSigningMethod(SigningMethodES256.Alg(), func() SigningMethod {
+		return SigningMethodES256
+	})
+
+	// ES384
+	SigningMethodES384 = &SigningMethodECDSA{"ES384", crypto.SHA384, 48, 384}
+	RegisterSigningMethod(SigningMethodES384.Alg(), func() SigningMethod {
+		return SigningMethodES384
+	})
+
+	// ES512
+	SigningMethodES512 = &SigningMethodECDSA{"ES512", crypto.SHA512, 66, 521}
+	RegisterSigningMethod(SigningMethodES512.Alg(), func() SigningMethod {
+		return SigningMethodES512
+	})
+}
+
+func (m *SigningMethodECDSA) Alg() string {
+	return m.Name
+}
+
+// Implements the Verify method from SigningMethod
+// For this verify method, key must be an ecdsa.PublicKey struct
+func (m *SigningMethodECDSA) Verify(signingString, signature string, key interface{}) error {
+	var err error
+
+	// Decode the signature
+	var sig []byte
+	if sig, err = DecodeSegment(signature); err != nil {
+		return err
+	}
+
+	// Get the key
+	var ecdsaKey *ecdsa.PublicKey
+	switch k := key.(type) {
+	case *ecdsa.PublicKey:
+		ecdsaKey = k
+	default:
+		return ErrInvalidKeyType
+	}
+
+	if len(sig) != 2*m.KeySize {
+		return ErrECDSAVerification
+	}
+
+	r := big.NewInt(0).SetBytes(sig[:m.KeySize])
+	s := big.NewInt(0).SetBytes(sig[m.KeySize:])
+
+	// Create hasher
+	if !m.Hash.Available() {
+		return ErrHashUnavailable
+	}
+	hasher := m.Hash.New()
+	hasher.Write([]byte(signingString))
+
+	// Verify the signature
+	if verifystatus := ecdsa.Verify(ecdsaKey, hasher.Sum(nil), r, s); verifystatus == true {
+		return nil
+	} else {
+		return ErrECDSAVerification
+	}
+}
+
+// Implements the Sign method from SigningMethod
+// For this signing method, key must be an ecdsa.PrivateKey struct
+func (m *SigningMethodECDSA) Sign(signingString string, key interface{}) (string, error) {
+	// Get the key
+	var ecdsaKey *ecdsa.PrivateKey
+	switch k := key.(type) {
+	case *ecdsa.PrivateKey:
+		ecdsaKey = k
+	default:
+		return "", ErrInvalidKeyType
+	}
+
+	// Create the hasher
+	if !m.Hash.Available() {
+		return "", ErrHashUnavailable
+	}
+
+	hasher := m.Hash.New()
+	hasher.Write([]byte(signingString))
+
+	// Sign the string and return r, s
+	if r, s, err := ecdsa.Sign(rand.Reader, ecdsaKey, hasher.Sum(nil)); err == nil {
+		curveBits := ecdsaKey.Curve.Params().BitSize
+
+		if m.CurveBits != curveBits {
+			return "", ErrInvalidKey
+		}
+
+		keyBytes := curveBits / 8
+		if curveBits%8 > 0 {
+			keyBytes += 1
+		}
+
+		// We serialize the outpus (r and s) into big-endian byte arrays and pad
+		// them with zeros on the left to make sure the sizes work out. Both arrays
+		// must be keyBytes long, and the output must be 2*keyBytes long.
+		rBytes := r.Bytes()
+		rBytesPadded := make([]byte, keyBytes)
+		copy(rBytesPadded[keyBytes-len(rBytes):], rBytes)
+
+		sBytes := s.Bytes()
+		sBytesPadded := make([]byte, keyBytes)
+		copy(sBytesPadded[keyBytes-len(sBytes):], sBytes)
+
+		out := append(rBytesPadded, sBytesPadded...)
+
+		return EncodeSegment(out), nil
+	} else {
+		return "", err
+	}
+}

+ 67 - 0
vendor/github.com/dgrijalva/jwt-go/ecdsa_utils.go

@@ -0,0 +1,67 @@
+package jwt
+
+import (
+	"crypto/ecdsa"
+	"crypto/x509"
+	"encoding/pem"
+	"errors"
+)
+
+var (
+	ErrNotECPublicKey  = errors.New("Key is not a valid ECDSA public key")
+	ErrNotECPrivateKey = errors.New("Key is not a valid ECDSA private key")
+)
+
+// Parse PEM encoded Elliptic Curve Private Key Structure
+func ParseECPrivateKeyFromPEM(key []byte) (*ecdsa.PrivateKey, error) {
+	var err error
+
+	// Parse PEM block
+	var block *pem.Block
+	if block, _ = pem.Decode(key); block == nil {
+		return nil, ErrKeyMustBePEMEncoded
+	}
+
+	// Parse the key
+	var parsedKey interface{}
+	if parsedKey, err = x509.ParseECPrivateKey(block.Bytes); err != nil {
+		return nil, err
+	}
+
+	var pkey *ecdsa.PrivateKey
+	var ok bool
+	if pkey, ok = parsedKey.(*ecdsa.PrivateKey); !ok {
+		return nil, ErrNotECPrivateKey
+	}
+
+	return pkey, nil
+}
+
+// Parse PEM encoded PKCS1 or PKCS8 public key
+func ParseECPublicKeyFromPEM(key []byte) (*ecdsa.PublicKey, error) {
+	var err error
+
+	// Parse PEM block
+	var block *pem.Block
+	if block, _ = pem.Decode(key); block == nil {
+		return nil, ErrKeyMustBePEMEncoded
+	}
+
+	// Parse the key
+	var parsedKey interface{}
+	if parsedKey, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil {
+		if cert, err := x509.ParseCertificate(block.Bytes); err == nil {
+			parsedKey = cert.PublicKey
+		} else {
+			return nil, err
+		}
+	}
+
+	var pkey *ecdsa.PublicKey
+	var ok bool
+	if pkey, ok = parsedKey.(*ecdsa.PublicKey); !ok {
+		return nil, ErrNotECPublicKey
+	}
+
+	return pkey, nil
+}

+ 59 - 0
vendor/github.com/dgrijalva/jwt-go/errors.go

@@ -0,0 +1,59 @@
+package jwt
+
+import (
+	"errors"
+)
+
+// Error constants
+var (
+	ErrInvalidKey      = errors.New("key is invalid")
+	ErrInvalidKeyType  = errors.New("key is of invalid type")
+	ErrHashUnavailable = errors.New("the requested hash function is unavailable")
+)
+
+// The errors that might occur when parsing and validating a token
+const (
+	ValidationErrorMalformed        uint32 = 1 << iota // Token is malformed
+	ValidationErrorUnverifiable                        // Token could not be verified because of signing problems
+	ValidationErrorSignatureInvalid                    // Signature validation failed
+
+	// Standard Claim validation errors
+	ValidationErrorAudience      // AUD validation failed
+	ValidationErrorExpired       // EXP validation failed
+	ValidationErrorIssuedAt      // IAT validation failed
+	ValidationErrorIssuer        // ISS validation failed
+	ValidationErrorNotValidYet   // NBF validation failed
+	ValidationErrorId            // JTI validation failed
+	ValidationErrorClaimsInvalid // Generic claims validation error
+)
+
+// Helper for constructing a ValidationError with a string error message
+func NewValidationError(errorText string, errorFlags uint32) *ValidationError {
+	return &ValidationError{
+		text:   errorText,
+		Errors: errorFlags,
+	}
+}
+
+// The error from Parse if token is not valid
+type ValidationError struct {
+	Inner  error  // stores the error returned by external dependencies, i.e.: KeyFunc
+	Errors uint32 // bitfield.  see ValidationError... constants
+	text   string // errors that do not have a valid error just have text
+}
+
+// Validation error is an error type
+func (e ValidationError) Error() string {
+	if e.Inner != nil {
+		return e.Inner.Error()
+	} else if e.text != "" {
+		return e.text
+	} else {
+		return "token is invalid"
+	}
+}
+
+// No errors
+func (e *ValidationError) valid() bool {
+	return e.Errors == 0
+}

+ 95 - 0
vendor/github.com/dgrijalva/jwt-go/hmac.go

@@ -0,0 +1,95 @@
+package jwt
+
+import (
+	"crypto"
+	"crypto/hmac"
+	"errors"
+)
+
+// Implements the HMAC-SHA family of signing methods signing methods
+// Expects key type of []byte for both signing and validation
+type SigningMethodHMAC struct {
+	Name string
+	Hash crypto.Hash
+}
+
+// Specific instances for HS256 and company
+var (
+	SigningMethodHS256  *SigningMethodHMAC
+	SigningMethodHS384  *SigningMethodHMAC
+	SigningMethodHS512  *SigningMethodHMAC
+	ErrSignatureInvalid = errors.New("signature is invalid")
+)
+
+func init() {
+	// HS256
+	SigningMethodHS256 = &SigningMethodHMAC{"HS256", crypto.SHA256}
+	RegisterSigningMethod(SigningMethodHS256.Alg(), func() SigningMethod {
+		return SigningMethodHS256
+	})
+
+	// HS384
+	SigningMethodHS384 = &SigningMethodHMAC{"HS384", crypto.SHA384}
+	RegisterSigningMethod(SigningMethodHS384.Alg(), func() SigningMethod {
+		return SigningMethodHS384
+	})
+
+	// HS512
+	SigningMethodHS512 = &SigningMethodHMAC{"HS512", crypto.SHA512}
+	RegisterSigningMethod(SigningMethodHS512.Alg(), func() SigningMethod {
+		return SigningMethodHS512
+	})
+}
+
+func (m *SigningMethodHMAC) Alg() string {
+	return m.Name
+}
+
+// Verify the signature of HSXXX tokens.  Returns nil if the signature is valid.
+func (m *SigningMethodHMAC) Verify(signingString, signature string, key interface{}) error {
+	// Verify the key is the right type
+	keyBytes, ok := key.([]byte)
+	if !ok {
+		return ErrInvalidKeyType
+	}
+
+	// Decode signature, for comparison
+	sig, err := DecodeSegment(signature)
+	if err != nil {
+		return err
+	}
+
+	// Can we use the specified hashing method?
+	if !m.Hash.Available() {
+		return ErrHashUnavailable
+	}
+
+	// This signing method is symmetric, so we validate the signature
+	// by reproducing the signature from the signing string and key, then
+	// comparing that against the provided signature.
+	hasher := hmac.New(m.Hash.New, keyBytes)
+	hasher.Write([]byte(signingString))
+	if !hmac.Equal(sig, hasher.Sum(nil)) {
+		return ErrSignatureInvalid
+	}
+
+	// No validation errors.  Signature is good.
+	return nil
+}
+
+// Implements the Sign method from SigningMethod for this signing method.
+// Key must be []byte
+func (m *SigningMethodHMAC) Sign(signingString string, key interface{}) (string, error) {
+	if keyBytes, ok := key.([]byte); ok {
+		if !m.Hash.Available() {
+			return "", ErrHashUnavailable
+		}
+
+		hasher := hmac.New(m.Hash.New, keyBytes)
+		hasher.Write([]byte(signingString))
+
+		return EncodeSegment(hasher.Sum(nil)), nil
+	}
+
+	return "", ErrInvalidKeyType
+}

+ 94 - 0
vendor/github.com/dgrijalva/jwt-go/map_claims.go

@@ -0,0 +1,94 @@
+package jwt
+
+import (
+	"encoding/json"
+	"errors"
+	// "fmt"
+)
+
+// Claims type that uses the map[string]interface{} for JSON decoding
+// This is the default claims type if you don't supply one
+type MapClaims map[string]interface{}
+
+// Compares the aud claim against cmp.
+// If required is false, this method will return true if the value matches or is unset
+func (m MapClaims) VerifyAudience(cmp string, req bool) bool {
+	aud, _ := m["aud"].(string)
+	return verifyAud(aud, cmp, req)
+}
+
+// Compares the exp claim against cmp.
+// If required is false, this method will return true if the value matches or is unset
+func (m MapClaims) VerifyExpiresAt(cmp int64, req bool) bool {
+	switch exp := m["exp"].(type) {
+	case float64:
+		return verifyExp(int64(exp), cmp, req)
+	case json.Number:
+		v, _ := exp.Int64()
+		return verifyExp(v, cmp, req)
+	}
+	return req == false
+}
+
+// Compares the iat claim against cmp.
+// If required is false, this method will return true if the value matches or is unset
+func (m MapClaims) VerifyIssuedAt(cmp int64, req bool) bool {
+	switch iat := m["iat"].(type) {
+	case float64:
+		return verifyIat(int64(iat), cmp, req)
+	case json.Number:
+		v, _ := iat.Int64()
+		return verifyIat(v, cmp, req)
+	}
+	return req == false
+}
+
+// Compares the iss claim against cmp.
+// If required is false, this method will return true if the value matches or is unset
+func (m MapClaims) VerifyIssuer(cmp string, req bool) bool {
+	iss, _ := m["iss"].(string)
+	return verifyIss(iss, cmp, req)
+}
+
+// Compares the nbf claim against cmp.
+// If required is false, this method will return true if the value matches or is unset
+func (m MapClaims) VerifyNotBefore(cmp int64, req bool) bool {
+	switch nbf := m["nbf"].(type) {
+	case float64:
+		return verifyNbf(int64(nbf), cmp, req)
+	case json.Number:
+		v, _ := nbf.Int64()
+		return verifyNbf(v, cmp, req)
+	}
+	return req == false
+}
+
+// Validates time based claims "exp, iat, nbf".
+// There is no accounting for clock skew.
+// As well, if any of the above claims are not in the token, it will still
+// be considered a valid claim.
+func (m MapClaims) Valid() error {
+	vErr := new(ValidationError)
+	now := TimeFunc().Unix()
+
+	if m.VerifyExpiresAt(now, false) == false {
+		vErr.Inner = errors.New("Token is expired")
+		vErr.Errors |= ValidationErrorExpired
+	}
+
+	if m.VerifyIssuedAt(now, false) == false {
+		vErr.Inner = errors.New("Token used before issued")
+		vErr.Errors |= ValidationErrorIssuedAt
+	}
+
+	if m.VerifyNotBefore(now, false) == false {
+		vErr.Inner = errors.New("Token is not valid yet")
+		vErr.Errors |= ValidationErrorNotValidYet
+	}
+
+	if vErr.valid() {
+		return nil
+	}
+
+	return vErr
+}

+ 52 - 0
vendor/github.com/dgrijalva/jwt-go/none.go

@@ -0,0 +1,52 @@
+package jwt
+
+// Implements the none signing method.  This is required by the spec
+// but you probably should never use it.
+var SigningMethodNone *signingMethodNone
+
+const UnsafeAllowNoneSignatureType unsafeNoneMagicConstant = "none signing method allowed"
+
+var NoneSignatureTypeDisallowedError error
+
+type signingMethodNone struct{}
+type unsafeNoneMagicConstant string
+
+func init() {
+	SigningMethodNone = &signingMethodNone{}
+	NoneSignatureTypeDisallowedError = NewValidationError("'none' signature type is not allowed", ValidationErrorSignatureInvalid)
+
+	RegisterSigningMethod(SigningMethodNone.Alg(), func() SigningMethod {
+		return SigningMethodNone
+	})
+}
+
+func (m *signingMethodNone) Alg() string {
+	return "none"
+}
+
+// Only allow 'none' alg type if UnsafeAllowNoneSignatureType is specified as the key
+func (m *signingMethodNone) Verify(signingString, signature string, key interface{}) (err error) {
+	// Key must be UnsafeAllowNoneSignatureType to prevent accidentally
+	// accepting 'none' signing method
+	if _, ok := key.(unsafeNoneMagicConstant); !ok {
+		return NoneSignatureTypeDisallowedError
+	}
+	// If signing method is none, signature must be an empty string
+	if signature != "" {
+		return NewValidationError(
+			"'none' signing method with non-empty signature",
+			ValidationErrorSignatureInvalid,
+		)
+	}
+
+	// Accept 'none' signing method.
+	return nil
+}
+
+// Only allow 'none' signing if UnsafeAllowNoneSignatureType is specified as the key
+func (m *signingMethodNone) Sign(signingString string, key interface{}) (string, error) {
+	if _, ok := key.(unsafeNoneMagicConstant); ok {
+		return "", nil
+	}
+	return "", NoneSignatureTypeDisallowedError
+}

+ 148 - 0
vendor/github.com/dgrijalva/jwt-go/parser.go

@@ -0,0 +1,148 @@
+package jwt
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"strings"
+)
+
+type Parser struct {
+	ValidMethods         []string // If populated, only these methods will be considered valid
+	UseJSONNumber        bool     // Use JSON Number format in JSON decoder
+	SkipClaimsValidation bool     // Skip claims validation during token parsing
+}
+
+// Parse, validate, and return a token.
+// keyFunc will receive the parsed token and should return the key for validating.
+// If everything is kosher, err will be nil
+func (p *Parser) Parse(tokenString string, keyFunc Keyfunc) (*Token, error) {
+	return p.ParseWithClaims(tokenString, MapClaims{}, keyFunc)
+}
+
+func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc) (*Token, error) {
+	token, parts, err := p.ParseUnverified(tokenString, claims)
+	if err != nil {
+		return token, err
+	}
+
+	// Verify signing method is in the required set
+	if p.ValidMethods != nil {
+		var signingMethodValid = false
+		var alg = token.Method.Alg()
+		for _, m := range p.ValidMethods {
+			if m == alg {
+				signingMethodValid = true
+				break
+			}
+		}
+		if !signingMethodValid {
+			// signing method is not in the listed set
+			return token, NewValidationError(fmt.Sprintf("signing method %v is invalid", alg), ValidationErrorSignatureInvalid)
+		}
+	}
+
+	// Lookup key
+	var key interface{}
+	if keyFunc == nil {
+		// keyFunc was not provided.  short circuiting validation
+		return token, NewValidationError("no Keyfunc was provided.", ValidationErrorUnverifiable)
+	}
+	if key, err = keyFunc(token); err != nil {
+		// keyFunc returned an error
+		if ve, ok := err.(*ValidationError); ok {
+			return token, ve
+		}
+		return token, &ValidationError{Inner: err, Errors: ValidationErrorUnverifiable}
+	}
+
+	vErr := &ValidationError{}
+
+	// Validate Claims
+	if !p.SkipClaimsValidation {
+		if err := token.Claims.Valid(); err != nil {
+
+			// If the Claims Valid returned an error, check if it is a validation error,
+			// If it was another error type, create a ValidationError with a generic ClaimsInvalid flag set
+			if e, ok := err.(*ValidationError); !ok {
+				vErr = &ValidationError{Inner: err, Errors: ValidationErrorClaimsInvalid}
+			} else {
+				vErr = e
+			}
+		}
+	}
+
+	// Perform validation
+	token.Signature = parts[2]
+	if err = token.Method.Verify(strings.Join(parts[0:2], "."), token.Signature, key); err != nil {
+		vErr.Inner = err
+		vErr.Errors |= ValidationErrorSignatureInvalid
+	}
+
+	if vErr.valid() {
+		token.Valid = true
+		return token, nil
+	}
+
+	return token, vErr
+}
+
+// WARNING: Don't use this method unless you know what you're doing
+//
+// This method parses the token but doesn't validate the signature. It's only
+// ever useful in cases where you know the signature is valid (because it has
+// been checked previously in the stack) and you want to extract values from
+// it.
+func (p *Parser) ParseUnverified(tokenString string, claims Claims) (token *Token, parts []string, err error) {
+	parts = strings.Split(tokenString, ".")
+	if len(parts) != 3 {
+		return nil, parts, NewValidationError("token contains an invalid number of segments", ValidationErrorMalformed)
+	}
+
+	token = &Token{Raw: tokenString}
+
+	// parse Header
+	var headerBytes []byte
+	if headerBytes, err = DecodeSegment(parts[0]); err != nil {
+		if strings.HasPrefix(strings.ToLower(tokenString), "bearer ") {
+			return token, parts, NewValidationError("tokenstring should not contain 'bearer '", ValidationErrorMalformed)
+		}
+		return token, parts, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
+	}
+	if err = json.Unmarshal(headerBytes, &token.Header); err != nil {
+		return token, parts, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
+	}
+
+	// parse Claims
+	var claimBytes []byte
+	token.Claims = claims
+
+	if claimBytes, err = DecodeSegment(parts[1]); err != nil {
+		return token, parts, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
+	}
+	dec := json.NewDecoder(bytes.NewBuffer(claimBytes))
+	if p.UseJSONNumber {
+		dec.UseNumber()
+	}
+	// JSON Decode.  Special case for map type to avoid weird pointer behavior
+	if c, ok := token.Claims.(MapClaims); ok {
+		err = dec.Decode(&c)
+	} else {
+		err = dec.Decode(&claims)
+	}
+	// Handle decode error
+	if err != nil {
+		return token, parts, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
+	}
+
+	// Lookup signature method
+	if method, ok := token.Header["alg"].(string); ok {
+		if token.Method = GetSigningMethod(method); token.Method == nil {
+			return token, parts, NewValidationError("signing method (alg) is unavailable.", ValidationErrorUnverifiable)
+		}
+	} else {
+		return token, parts, NewValidationError("signing method (alg) is unspecified.", ValidationErrorUnverifiable)
+	}
+
+	return token, parts, nil
+}

+ 101 - 0
vendor/github.com/dgrijalva/jwt-go/rsa.go

@@ -0,0 +1,101 @@
+package jwt
+
+import (
+	"crypto"
+	"crypto/rand"
+	"crypto/rsa"
+)
+
+// Implements the RSA family of signing methods signing methods
+// Expects *rsa.PrivateKey for signing and *rsa.PublicKey for validation
+type SigningMethodRSA struct {
+	Name string
+	Hash crypto.Hash
+}
+
+// Specific instances for RS256 and company
+var (
+	SigningMethodRS256 *SigningMethodRSA
+	SigningMethodRS384 *SigningMethodRSA
+	SigningMethodRS512 *SigningMethodRSA
+)
+
+func init() {
+	// RS256
+	SigningMethodRS256 = &SigningMethodRSA{"RS256", crypto.SHA256}
+	RegisterSigningMethod(SigningMethodRS256.Alg(), func() SigningMethod {
+		return SigningMethodRS256
+	})
+
+	// RS384
+	SigningMethodRS384 = &SigningMethodRSA{"RS384", crypto.SHA384}
+	RegisterSigningMethod(SigningMethodRS384.Alg(), func() SigningMethod {
+		return SigningMethodRS384
+	})
+
+	// RS512
+	SigningMethodRS512 = &SigningMethodRSA{"RS512", crypto.SHA512}
+	RegisterSigningMethod(SigningMethodRS512.Alg(), func() SigningMethod {
+		return SigningMethodRS512
+	})
+}
+
+func (m *SigningMethodRSA) Alg() string {
+	return m.Name
+}
+
+// Implements the Verify method from SigningMethod
+// For this signing method, must be an *rsa.PublicKey structure.
+func (m *SigningMethodRSA) Verify(signingString, signature string, key interface{}) error {
+	var err error
+
+	// Decode the signature
+	var sig []byte
+	if sig, err = DecodeSegment(signature); err != nil {
+		return err
+	}
+
+	var rsaKey *rsa.PublicKey
+	var ok bool
+
+	if rsaKey, ok = key.(*rsa.PublicKey); !ok {
+		return ErrInvalidKeyType
+	}
+
+	// Create hasher
+	if !m.Hash.Available() {
+		return ErrHashUnavailable
+	}
+	hasher := m.Hash.New()
+	hasher.Write([]byte(signingString))
+
+	// Verify the signature
+	return rsa.VerifyPKCS1v15(rsaKey, m.Hash, hasher.Sum(nil), sig)
+}
+
+// Implements the Sign method from SigningMethod
+// For this signing method, must be an *rsa.PrivateKey structure.
+func (m *SigningMethodRSA) Sign(signingString string, key interface{}) (string, error) {
+	var rsaKey *rsa.PrivateKey
+	var ok bool
+
+	// Validate type of key
+	if rsaKey, ok = key.(*rsa.PrivateKey); !ok {
+		return "", ErrInvalidKey
+	}
+
+	// Create the hasher
+	if !m.Hash.Available() {
+		return "", ErrHashUnavailable
+	}
+
+	hasher := m.Hash.New()
+	hasher.Write([]byte(signingString))
+
+	// Sign the string and return the encoded bytes
+	if sigBytes, err := rsa.SignPKCS1v15(rand.Reader, rsaKey, m.Hash, hasher.Sum(nil)); err == nil {
+		return EncodeSegment(sigBytes), nil
+	} else {
+		return "", err
+	}
+}

+ 126 - 0
vendor/github.com/dgrijalva/jwt-go/rsa_pss.go

@@ -0,0 +1,126 @@
+// +build go1.4
+
+package jwt
+
+import (
+	"crypto"
+	"crypto/rand"
+	"crypto/rsa"
+)
+
+// Implements the RSAPSS family of signing methods signing methods
+type SigningMethodRSAPSS struct {
+	*SigningMethodRSA
+	Options *rsa.PSSOptions
+}
+
+// Specific instances for RS/PS and company
+var (
+	SigningMethodPS256 *SigningMethodRSAPSS
+	SigningMethodPS384 *SigningMethodRSAPSS
+	SigningMethodPS512 *SigningMethodRSAPSS
+)
+
+func init() {
+	// PS256
+	SigningMethodPS256 = &SigningMethodRSAPSS{
+		&SigningMethodRSA{
+			Name: "PS256",
+			Hash: crypto.SHA256,
+		},
+		&rsa.PSSOptions{
+			SaltLength: rsa.PSSSaltLengthAuto,
+			Hash:       crypto.SHA256,
+		},
+	}
+	RegisterSigningMethod(SigningMethodPS256.Alg(), func() SigningMethod {
+		return SigningMethodPS256
+	})
+
+	// PS384
+	SigningMethodPS384 = &SigningMethodRSAPSS{
+		&SigningMethodRSA{
+			Name: "PS384",
+			Hash: crypto.SHA384,
+		},
+		&rsa.PSSOptions{
+			SaltLength: rsa.PSSSaltLengthAuto,
+			Hash:       crypto.SHA384,
+		},
+	}
+	RegisterSigningMethod(SigningMethodPS384.Alg(), func() SigningMethod {
+		return SigningMethodPS384
+	})
+
+	// PS512
+	SigningMethodPS512 = &SigningMethodRSAPSS{
+		&SigningMethodRSA{
+			Name: "PS512",
+			Hash: crypto.SHA512,
+		},
+		&rsa.PSSOptions{
+			SaltLength: rsa.PSSSaltLengthAuto,
+			Hash:       crypto.SHA512,
+		},
+	}
+	RegisterSigningMethod(SigningMethodPS512.Alg(), func() SigningMethod {
+		return SigningMethodPS512
+	})
+}
+
+// Implements the Verify method from SigningMethod
+// For this verify method, key must be an rsa.PublicKey struct
+func (m *SigningMethodRSAPSS) Verify(signingString, signature string, key interface{}) error {
+	var err error
+
+	// Decode the signature
+	var sig []byte
+	if sig, err = DecodeSegment(signature); err != nil {
+		return err
+	}
+
+	var rsaKey *rsa.PublicKey
+	switch k := key.(type) {
+	case *rsa.PublicKey:
+		rsaKey = k
+	default:
+		return ErrInvalidKey
+	}
+
+	// Create hasher
+	if !m.Hash.Available() {
+		return ErrHashUnavailable
+	}
+	hasher := m.Hash.New()
+	hasher.Write([]byte(signingString))
+
+	return rsa.VerifyPSS(rsaKey, m.Hash, hasher.Sum(nil), sig, m.Options)
+}
+
+// Implements the Sign method from SigningMethod
+// For this signing method, key must be an rsa.PrivateKey struct
+func (m *SigningMethodRSAPSS) Sign(signingString string, key interface{}) (string, error) {
+	var rsaKey *rsa.PrivateKey
+
+	switch k := key.(type) {
+	case *rsa.PrivateKey:
+		rsaKey = k
+	default:
+		return "", ErrInvalidKeyType
+	}
+
+	// Create the hasher
+	if !m.Hash.Available() {
+		return "", ErrHashUnavailable
+	}
+
+	hasher := m.Hash.New()
+	hasher.Write([]byte(signingString))
+
+	// Sign the string and return the encoded bytes
+	if sigBytes, err := rsa.SignPSS(rand.Reader, rsaKey, m.Hash, hasher.Sum(nil), m.Options); err == nil {
+		return EncodeSegment(sigBytes), nil
+	} else {
+		return "", err
+	}
+}

+ 101 - 0
vendor/github.com/dgrijalva/jwt-go/rsa_utils.go

@@ -0,0 +1,101 @@
+package jwt
+
+import (
+	"crypto/rsa"
+	"crypto/x509"
+	"encoding/pem"
+	"errors"
+)
+
+var (
+	ErrKeyMustBePEMEncoded = errors.New("Invalid Key: Key must be PEM encoded PKCS1 or PKCS8 private key")
+	ErrNotRSAPrivateKey    = errors.New("Key is not a valid RSA private key")
+	ErrNotRSAPublicKey     = errors.New("Key is not a valid RSA public key")
+)
+
+// Parse PEM encoded PKCS1 or PKCS8 private key
+func ParseRSAPrivateKeyFromPEM(key []byte) (*rsa.PrivateKey, error) {
+	var err error
+
+	// Parse PEM block
+	var block *pem.Block
+	if block, _ = pem.Decode(key); block == nil {
+		return nil, ErrKeyMustBePEMEncoded
+	}
+
+	var parsedKey interface{}
+	if parsedKey, err = x509.ParsePKCS1PrivateKey(block.Bytes); err != nil {
+		if parsedKey, err = x509.ParsePKCS8PrivateKey(block.Bytes); err != nil {
+			return nil, err
+		}
+	}
+
+	var pkey *rsa.PrivateKey
+	var ok bool
+	if pkey, ok = parsedKey.(*rsa.PrivateKey); !ok {
+		return nil, ErrNotRSAPrivateKey
+	}
+
+	return pkey, nil
+}
+
+// Parse PEM encoded PKCS1 or PKCS8 private key protected with password
+func ParseRSAPrivateKeyFromPEMWithPassword(key []byte, password string) (*rsa.PrivateKey, error) {
+	var err error
+
+	// Parse PEM block
+	var block *pem.Block
+	if block, _ = pem.Decode(key); block == nil {
+		return nil, ErrKeyMustBePEMEncoded
+	}
+
+	var parsedKey interface{}
+
+	var blockDecrypted []byte
+	if blockDecrypted, err = x509.DecryptPEMBlock(block, []byte(password)); err != nil {
+		return nil, err
+	}
+
+	if parsedKey, err = x509.ParsePKCS1PrivateKey(blockDecrypted); err != nil {
+		if parsedKey, err = x509.ParsePKCS8PrivateKey(blockDecrypted); err != nil {
+			return nil, err
+		}
+	}
+
+	var pkey *rsa.PrivateKey
+	var ok bool
+	if pkey, ok = parsedKey.(*rsa.PrivateKey); !ok {
+		return nil, ErrNotRSAPrivateKey
+	}
+
+	return pkey, nil
+}
+
+// Parse PEM encoded PKCS1 or PKCS8 public key
+func ParseRSAPublicKeyFromPEM(key []byte) (*rsa.PublicKey, error) {
+	var err error
+
+	// Parse PEM block
+	var block *pem.Block
+	if block, _ = pem.Decode(key); block == nil {
+		return nil, ErrKeyMustBePEMEncoded
+	}
+
+	// Parse the key
+	var parsedKey interface{}
+	if parsedKey, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil {
+		if cert, err := x509.ParseCertificate(block.Bytes); err == nil {
+			parsedKey = cert.PublicKey
+		} else {
+			return nil, err
+		}
+	}
+
+	var pkey *rsa.PublicKey
+	var ok bool
+	if pkey, ok = parsedKey.(*rsa.PublicKey); !ok {
+		return nil, ErrNotRSAPublicKey
+	}
+
+	return pkey, nil
+}

+ 35 - 0
vendor/github.com/dgrijalva/jwt-go/signing_method.go

@@ -0,0 +1,35 @@
+package jwt
+
+import (
+	"sync"
+)
+
+var signingMethods = map[string]func() SigningMethod{}
+var signingMethodLock = new(sync.RWMutex)
+
+// Implement SigningMethod to add new methods for signing or verifying tokens.
+type SigningMethod interface {
+	Verify(signingString, signature string, key interface{}) error // Returns nil if signature is valid
+	Sign(signingString string, key interface{}) (string, error)    // Returns encoded signature or error
+	Alg() string                                                   // returns the alg identifier for this method (example: 'HS256')
+}
+
+// Register the "alg" name and a factory function for signing method.
+// This is typically done during init() in the method's implementation
+func RegisterSigningMethod(alg string, f func() SigningMethod) {
+	signingMethodLock.Lock()
+	defer signingMethodLock.Unlock()
+
+	signingMethods[alg] = f
+}
+
+// Get a signing method from an "alg" string
+func GetSigningMethod(alg string) (method SigningMethod) {
+	signingMethodLock.RLock()
+	defer signingMethodLock.RUnlock()
+
+	if methodF, ok := signingMethods[alg]; ok {
+		method = methodF()
+	}
+	return
+}

+ 108 - 0
vendor/github.com/dgrijalva/jwt-go/token.go

@@ -0,0 +1,108 @@
+package jwt
+
+import (
+	"encoding/base64"
+	"encoding/json"
+	"strings"
+	"time"
+)
+
+// TimeFunc provides the current time when parsing token to validate "exp" claim (expiration time).
+// You can override it to use another time value.  This is useful for testing or if your
+// server uses a different time zone than your tokens.
+var TimeFunc = time.Now
+
+// Parse methods use this callback function to supply
+// the key for verification.  The function receives the parsed,
+// but unverified Token.  This allows you to use properties in the
+// Header of the token (such as `kid`) to identify which key to use.
+type Keyfunc func(*Token) (interface{}, error)
+
+// A JWT Token.  Different fields will be used depending on whether you're
+// creating or parsing/verifying a token.
+type Token struct {
+	Raw       string                 // The raw token.  Populated when you Parse a token
+	Method    SigningMethod          // The signing method used or to be used
+	Header    map[string]interface{} // The first segment of the token
+	Claims    Claims                 // The second segment of the token
+	Signature string                 // The third segment of the token.  Populated when you Parse a token
+	Valid     bool                   // Is the token valid?  Populated when you Parse/Verify a token
+}
+
+// Create a new Token.  Takes a signing method
+func New(method SigningMethod) *Token {
+	return NewWithClaims(method, MapClaims{})
+}
+
+func NewWithClaims(method SigningMethod, claims Claims) *Token {
+	return &Token{
+		Header: map[string]interface{}{
+			"typ": "JWT",
+			"alg": method.Alg(),
+		},
+		Claims: claims,
+		Method: method,
+	}
+}
+
+// Get the complete, signed token
+func (t *Token) SignedString(key interface{}) (string, error) {
+	var sig, sstr string
+	var err error
+	if sstr, err = t.SigningString(); err != nil {
+		return "", err
+	}
+	if sig, err = t.Method.Sign(sstr, key); err != nil {
+		return "", err
+	}
+	return strings.Join([]string{sstr, sig}, "."), nil
+}
+
+// Generate the signing string.  This is the
+// most expensive part of the whole deal.  Unless you
+// need this for something special, just go straight for
+// the SignedString.
+func (t *Token) SigningString() (string, error) {
+	var err error
+	parts := make([]string, 2)
+	for i, _ := range parts {
+		var jsonValue []byte
+		if i == 0 {
+			if jsonValue, err = json.Marshal(t.Header); err != nil {
+				return "", err
+			}
+		} else {
+			if jsonValue, err = json.Marshal(t.Claims); err != nil {
+				return "", err
+			}
+		}
+
+		parts[i] = EncodeSegment(jsonValue)
+	}
+	return strings.Join(parts, "."), nil
+}
+
+// Parse, validate, and return a token.
+// keyFunc will receive the parsed token and should return the key for validating.
+// If everything is kosher, err will be nil
+func Parse(tokenString string, keyFunc Keyfunc) (*Token, error) {
+	return new(Parser).Parse(tokenString, keyFunc)
+}
+
+func ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc) (*Token, error) {
+	return new(Parser).ParseWithClaims(tokenString, claims, keyFunc)
+}
+
+// Encode JWT specific base64url encoding with padding stripped
+func EncodeSegment(seg []byte) string {
+	return strings.TrimRight(base64.URLEncoding.EncodeToString(seg), "=")
+}
+
+// Decode JWT specific base64url encoding with padding stripped
+func DecodeSegment(seg string) ([]byte, error) {
+	if l := len(seg) % 4; l > 0 {
+		seg += strings.Repeat("=", 4-l)
+	}
+
+	return base64.URLEncoding.DecodeString(seg)
+}

+ 25 - 0
vendor/github.com/labstack/echo/.editorconfig

@@ -0,0 +1,25 @@
+# EditorConfig coding styles definitions. For more information about the
+# properties used in this file, please see the EditorConfig documentation:
+# http://editorconfig.org/
+
+# indicate this is the root of the project
+root = true
+
+[*]
+charset = utf-8
+
+end_of_line = LF
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+indent_style = space
+indent_size = 2
+
+[Makefile]
+indent_style = tab
+
+[*.md]
+trim_trailing_whitespace = false
+
+[*.go]
+indent_style = tab

+ 20 - 0
vendor/github.com/labstack/echo/.gitattributes

@@ -0,0 +1,20 @@
+# Automatically normalize line endings for all text-based files
+# http://git-scm.com/docs/gitattributes#_end_of_line_conversion
+* text=auto
+
+# For the following file types, normalize line endings to LF on checking and
+# prevent conversion to CRLF when they are checked out (this is required in
+# order to prevent newline related issues)
+.*      text eol=lf
+*.go    text eol=lf
+*.yml   text eol=lf
+*.html  text eol=lf
+*.css   text eol=lf
+*.js    text eol=lf
+*.json  text eol=lf
+LICENSE text eol=lf
+
+# Exclude `website` and `cookbook` from GitHub's language statistics
+# https://github.com/github/linguist#using-gitattributes
+cookbook/* linguist-documentation
+website/* linguist-documentation

+ 7 - 0
vendor/github.com/labstack/echo/.gitignore

@@ -0,0 +1,7 @@
+.DS_Store
+coverage.txt
+_test
+vendor
+.idea
+*.iml
+*.out

+ 15 - 0
vendor/github.com/labstack/echo/.travis.yml

@@ -0,0 +1,15 @@
+language: go
+go:
+  - 1.9.x
+  - 1.10.x
+  - 1.11.x
+  - tip
+install:
+  - make dependency
+script:
+  - make test
+after_success:
+  - bash <(curl -s https://codecov.io/bash)
+matrix:
+  allow_failures:
+    - go: tip

+ 114 - 0
vendor/github.com/labstack/echo/Gopkg.lock

@@ -0,0 +1,114 @@
+# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
+
+
+[[projects]]
+  digest = "1:ffe9824d294da03b391f44e1ae8281281b4afc1bdaa9588c9097785e3af10cec"
+  name = "github.com/davecgh/go-spew"
+  packages = ["spew"]
+  pruneopts = "UT"
+  revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73"
+  version = "v1.1.1"
+
+[[projects]]
+  digest = "1:76dc72490af7174349349838f2fe118996381b31ea83243812a97e5a0fd5ed55"
+  name = "github.com/dgrijalva/jwt-go"
+  packages = ["."]
+  pruneopts = "UT"
+  revision = "06ea1031745cb8b3dab3f6a236daf2b0aa468b7e"
+  version = "v3.2.0"
+
+[[projects]]
+  digest = "1:568171fc14a3d819b112c3e219d351ea7b05e8dad7935c4168c6b3373244a686"
+  name = "github.com/labstack/gommon"
+  packages = [
+    "bytes",
+    "color",
+    "log",
+    "random",
+  ]
+  pruneopts = "UT"
+  revision = "2a618302b929cc20862dda3aa6f02f64dbe740dd"
+  version = "v0.2.7"
+
+[[projects]]
+  digest = "1:c658e84ad3916da105a761660dcaeb01e63416c8ec7bc62256a9b411a05fcd67"
+  name = "github.com/mattn/go-colorable"
+  packages = ["."]
+  pruneopts = "UT"
+  revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072"
+  version = "v0.0.9"
+
+[[projects]]
+  digest = "1:0981502f9816113c9c8c4ac301583841855c8cf4da8c72f696b3ebedf6d0e4e5"
+  name = "github.com/mattn/go-isatty"
+  packages = ["."]
+  pruneopts = "UT"
+  revision = "6ca4dbf54d38eea1a992b3c722a76a5d1c4cb25c"
+  version = "v0.0.4"
+
+[[projects]]
+  digest = "1:0028cb19b2e4c3112225cd871870f2d9cf49b9b4276531f03438a88e94be86fe"
+  name = "github.com/pmezard/go-difflib"
+  packages = ["difflib"]
+  pruneopts = "UT"
+  revision = "792786c7400a136282c1664665ae0a8db921c6c2"
+  version = "v1.0.0"
+
+[[projects]]
+  digest = "1:18752d0b95816a1b777505a97f71c7467a8445b8ffb55631a7bf779f6ba4fa83"
+  name = "github.com/stretchr/testify"
+  packages = ["assert"]
+  pruneopts = "UT"
+  revision = "f35b8ab0b5a2cef36673838d662e249dd9c94686"
+  version = "v1.2.2"
+
+[[projects]]
+  digest = "1:c468422f334a6b46a19448ad59aaffdfc0a36b08fdcc1c749a0b29b6453d7e59"
+  name = "github.com/valyala/bytebufferpool"
+  packages = ["."]
+  pruneopts = "UT"
+  revision = "e746df99fe4a3986f4d4f79e13c1e0117ce9c2f7"
+  version = "v1.0.0"
+
+[[projects]]
+  branch = "master"
+  digest = "1:268b8bce0064e8c057d7b913605459f9a26dcab864c0886a56d196540fbf003f"
+  name = "github.com/valyala/fasttemplate"
+  packages = ["."]
+  pruneopts = "UT"
+  revision = "dcecefd839c4193db0d35b88ec65b4c12d360ab0"
+
+[[projects]]
+  branch = "master"
+  digest = "1:dedf20eb0d3e8d6aa8a4d3d2fae248222b688ed528201995e152cc497899123c"
+  name = "golang.org/x/crypto"
+  packages = [
+    "acme",
+    "acme/autocert",
+  ]
+  pruneopts = "UT"
+  revision = "0e37d006457bf46f9e6692014ba72ef82c33022c"
+
+[[projects]]
+  branch = "master"
+  digest = "1:6eb2645d74b43d9c87b51947df39f7c668a4f422cd512053f7f6f75bfaad0197"
+  name = "golang.org/x/sys"
+  packages = ["unix"]
+  pruneopts = "UT"
+  revision = "d0be0721c37eeb5299f245a996a483160fc36940"
+
+[solve-meta]
+  analyzer-name = "dep"
+  analyzer-version = 1
+  input-imports = [
+    "github.com/dgrijalva/jwt-go",
+    "github.com/labstack/gommon/bytes",
+    "github.com/labstack/gommon/color",
+    "github.com/labstack/gommon/log",
+    "github.com/labstack/gommon/random",
+    "github.com/stretchr/testify/assert",
+    "github.com/valyala/fasttemplate",
+    "golang.org/x/crypto/acme/autocert",
+  ]
+  solver-name = "gps-cdcl"
+  solver-version = 1

+ 50 - 0
vendor/github.com/labstack/echo/Gopkg.toml

@@ -0,0 +1,50 @@
+# Gopkg.toml example
+#
+# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html
+# for detailed Gopkg.toml documentation.
+#
+# required = ["github.com/user/thing/cmd/thing"]
+# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
+#
+# [[constraint]]
+#   name = "github.com/user/project"
+#   version = "1.0.0"
+#
+# [[constraint]]
+#   name = "github.com/user/project2"
+#   branch = "dev"
+#   source = "github.com/myfork/project2"
+#
+# [[override]]
+#   name = "github.com/x/y"
+#   version = "2.4.0"
+#
+# [prune]
+#   non-go = false
+#   go-tests = true
+#   unused-packages = true
+
+
+[[constraint]]
+  name = "github.com/dgrijalva/jwt-go"
+  version = "3.2.0"
+
+[[constraint]]
+  name = "github.com/labstack/gommon"
+  version = "0.2.7"
+
+[[constraint]]
+  name = "github.com/stretchr/testify"
+  version = "1.2.2"
+
+[[constraint]]
+  branch = "master"
+  name = "github.com/valyala/fasttemplate"
+
+[[constraint]]
+  branch = "master"
+  name = "golang.org/x/crypto"
+
+[prune]
+  go-tests = true
+  unused-packages = true

+ 21 - 0
vendor/github.com/labstack/echo/LICENSE

@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2017 LabStack
+
+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.

+ 17 - 0
vendor/github.com/labstack/echo/Makefile

@@ -0,0 +1,17 @@
+DEP_VERSION=0.4.1
+
+dependency:
+	curl -fsSL -o ${GOPATH}/bin/dep https://github.com/golang/dep/releases/download/v${DEP_VERSION}/dep-linux-amd64
+	chmod +x ${GOPATH}/bin/dep
+	dep ensure
+
+test:
+	echo "" > coverage.txt
+	for d in $(shell go list ./... | grep -v vendor); do \
+		go test -race -coverprofile=profile.out -covermode=atomic $$d || exit 1; \
+		[ -f profile.out ] && cat profile.out >> coverage.txt && rm profile.out; \
+	done
+
+tag:
+	@git tag `grep -P '^\tversion = ' echo.go|cut -f2 -d'"'`
+	@git tag|grep -v ^v

+ 99 - 0
vendor/github.com/labstack/echo/README.md

@@ -0,0 +1,99 @@
+<a href="https://echo.labstack.com"><img height="80" src="https://cdn.labstack.com/images/echo-logo.svg"></a>
+
+[![Sourcegraph](https://sourcegraph.com/github.com/labstack/echo/-/badge.svg?style=flat-square)](https://sourcegraph.com/github.com/labstack/echo?badge)
+[![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](http://godoc.org/github.com/labstack/echo)
+[![Go Report Card](https://goreportcard.com/badge/github.com/labstack/echo?style=flat-square)](https://goreportcard.com/report/github.com/labstack/echo)
+[![Build Status](http://img.shields.io/travis/labstack/echo.svg?style=flat-square)](https://travis-ci.org/labstack/echo)
+[![Codecov](https://img.shields.io/codecov/c/github/labstack/echo.svg?style=flat-square)](https://codecov.io/gh/labstack/echo) 
+[![Join the chat at https://gitter.im/labstack/echo](https://img.shields.io/badge/gitter-join%20chat-brightgreen.svg?style=flat-square)](https://gitter.im/labstack/echo)
+[![Forum](https://img.shields.io/badge/community-forum-00afd1.svg?style=flat-square)](https://forum.labstack.com)
+[![Twitter](https://img.shields.io/badge/twitter-@labstack-55acee.svg?style=flat-square)](https://twitter.com/labstack)
+[![License](http://img.shields.io/badge/license-mit-blue.svg?style=flat-square)](https://raw.githubusercontent.com/labstack/echo/master/LICENSE)
+
+## Feature Overview
+
+- Optimized HTTP router which smartly prioritize routes
+- Build robust and scalable RESTful APIs
+- Group APIs
+- Extensible middleware framework
+- Define middleware at root, group or route level
+- Data binding for JSON, XML and form payload
+- Handy functions to send variety of HTTP responses
+- Centralized HTTP error handling
+- Template rendering with any template engine
+- Define your format for the logger
+- Highly customizable
+- Automatic TLS via Let’s Encrypt
+- HTTP/2 support
+
+## Benchmarks
+
+Date: 2018/03/15<br>
+Source: https://github.com/vishr/web-framework-benchmark<br>
+Lower is better!
+
+<img src="https://i.imgur.com/I32VdMJ.png">
+
+## [Guide](https://echo.labstack.com/guide)
+
+### Example
+
+```go
+package main
+
+import (
+	"net/http"
+
+	"github.com/labstack/echo"
+	"github.com/labstack/echo/middleware"
+)
+
+func main() {
+	// Echo instance
+	e := echo.New()
+
+	// Middleware
+	e.Use(middleware.Logger())
+	e.Use(middleware.Recover())
+
+	// Routes
+	e.GET("/", hello)
+
+	// Start server
+	e.Logger.Fatal(e.Start(":1323"))
+}
+
+// Handler
+func hello(c echo.Context) error {
+	return c.String(http.StatusOK, "Hello, World!")
+}
+```
+
+## Help
+
+- [Forum](https://forum.labstack.com)
+- [Chat](https://gitter.im/labstack/echo)
+
+## Contribute
+
+**Use issues for everything**
+
+- For a small change, just send a PR.
+- For bigger changes open an issue for discussion before sending a PR.
+- PR should have:
+  - Test case
+  - Documentation
+  - Example (If it makes sense)
+- You can also contribute by:
+  - Reporting issues
+  - Suggesting new features or enhancements
+  - Improve/fix documentation
+
+## Credits
+- [Vishal Rana](https://github.com/vishr) - Author
+- [Nitin Rana](https://github.com/nr17) - Consultant
+- [Contributors](https://github.com/labstack/echo/graphs/contributors)
+
+## License
+
+[MIT](https://github.com/labstack/echo/blob/master/LICENSE)

+ 273 - 0
vendor/github.com/labstack/echo/bind.go

@@ -0,0 +1,273 @@
+package echo
+
+import (
+	"encoding/json"
+	"encoding/xml"
+	"errors"
+	"fmt"
+	"net/http"
+	"reflect"
+	"strconv"
+	"strings"
+)
+
+type (
+	// Binder is the interface that wraps the Bind method.
+	Binder interface {
+		Bind(i interface{}, c Context) error
+	}
+
+	// DefaultBinder is the default implementation of the Binder interface.
+	DefaultBinder struct{}
+
+	// BindUnmarshaler is the interface used to wrap the UnmarshalParam method.
+	BindUnmarshaler interface {
+		// UnmarshalParam decodes and assigns a value from an form or query param.
+		UnmarshalParam(param string) error
+	}
+)
+
+// Bind implements the `Binder#Bind` function.
+func (b *DefaultBinder) Bind(i interface{}, c Context) (err error) {
+	req := c.Request()
+	if req.ContentLength == 0 {
+		if req.Method == GET || req.Method == DELETE {
+			if err = b.bindData(i, c.QueryParams(), "query"); err != nil {
+				return NewHTTPError(http.StatusBadRequest, err.Error())
+			}
+			return
+		}
+		return NewHTTPError(http.StatusBadRequest, "Request body can't be empty")
+	}
+	ctype := req.Header.Get(HeaderContentType)
+	switch {
+	case strings.HasPrefix(ctype, MIMEApplicationJSON):
+		if err = json.NewDecoder(req.Body).Decode(i); err != nil {
+			if ute, ok := err.(*json.UnmarshalTypeError); ok {
+				return NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Unmarshal type error: expected=%v, got=%v, field=%v, offset=%v", ute.Type, ute.Value, ute.Field, ute.Offset))
+			} else if se, ok := err.(*json.SyntaxError); ok {
+				return NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Syntax error: offset=%v, error=%v", se.Offset, se.Error()))
+			}
+			return NewHTTPError(http.StatusBadRequest, err.Error())
+		}
+	case strings.HasPrefix(ctype, MIMEApplicationXML), strings.HasPrefix(ctype, MIMETextXML):
+		if err = xml.NewDecoder(req.Body).Decode(i); err != nil {
+			if ute, ok := err.(*xml.UnsupportedTypeError); ok {
+				return NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Unsupported type error: type=%v, error=%v", ute.Type, ute.Error()))
+			} else if se, ok := err.(*xml.SyntaxError); ok {
+				return NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Syntax error: line=%v, error=%v", se.Line, se.Error()))
+			}
+			return NewHTTPError(http.StatusBadRequest, err.Error())
+		}
+	case strings.HasPrefix(ctype, MIMEApplicationForm), strings.HasPrefix(ctype, MIMEMultipartForm):
+		params, err := c.FormParams()
+		if err != nil {
+			return NewHTTPError(http.StatusBadRequest, err.Error())
+		}
+		if err = b.bindData(i, params, "form"); err != nil {
+			return NewHTTPError(http.StatusBadRequest, err.Error())
+		}
+	default:
+		return ErrUnsupportedMediaType
+	}
+	return
+}
+
+func (b *DefaultBinder) bindData(ptr interface{}, data map[string][]string, tag string) error {
+	typ := reflect.TypeOf(ptr).Elem()
+	val := reflect.ValueOf(ptr).Elem()
+
+	if typ.Kind() != reflect.Struct {
+		return errors.New("binding element must be a struct")
+	}
+
+	for i := 0; i < typ.NumField(); i++ {
+		typeField := typ.Field(i)
+		structField := val.Field(i)
+		if !structField.CanSet() {
+			continue
+		}
+		structFieldKind := structField.Kind()
+		inputFieldName := typeField.Tag.Get(tag)
+
+		if inputFieldName == "" {
+			inputFieldName = typeField.Name
+			// If tag is nil, we inspect if the field is a struct.
+			if _, ok := bindUnmarshaler(structField); !ok && structFieldKind == reflect.Struct {
+				if err := b.bindData(structField.Addr().Interface(), data, tag); err != nil {
+					return err
+				}
+				continue
+			}
+		}
+
+		inputValue, exists := data[inputFieldName]
+		if !exists {
+			// Go json.Unmarshal supports case insensitive binding.  However the
+			// url params are bound case sensitive which is inconsistent.  To
+			// fix this we must check all of the map values in a
+			// case-insensitive search.
+			inputFieldName = strings.ToLower(inputFieldName)
+			for k, v := range data {
+				if strings.ToLower(k) == inputFieldName {
+					inputValue = v
+					exists = true
+					break
+				}
+			}
+		}
+
+		if !exists {
+			continue
+		}
+
+		// Call this first, in case we're dealing with an alias to an array type
+		if ok, err := unmarshalField(typeField.Type.Kind(), inputValue[0], structField); ok {
+			if err != nil {
+				return err
+			}
+			continue
+		}
+
+		numElems := len(inputValue)
+		if structFieldKind == reflect.Slice && numElems > 0 {
+			sliceOf := structField.Type().Elem().Kind()
+			slice := reflect.MakeSlice(structField.Type(), numElems, numElems)
+			for j := 0; j < numElems; j++ {
+				if err := setWithProperType(sliceOf, inputValue[j], slice.Index(j)); err != nil {
+					return err
+				}
+			}
+			val.Field(i).Set(slice)
+		} else if err := setWithProperType(typeField.Type.Kind(), inputValue[0], structField); err != nil {
+			return err
+
+		}
+	}
+	return nil
+}
+
+func setWithProperType(valueKind reflect.Kind, val string, structField reflect.Value) error {
+	// But also call it here, in case we're dealing with an array of BindUnmarshalers
+	if ok, err := unmarshalField(valueKind, val, structField); ok {
+		return err
+	}
+
+	switch valueKind {
+	case reflect.Ptr:
+		return setWithProperType(structField.Elem().Kind(), val, structField.Elem())
+	case reflect.Int:
+		return setIntField(val, 0, structField)
+	case reflect.Int8:
+		return setIntField(val, 8, structField)
+	case reflect.Int16:
+		return setIntField(val, 16, structField)
+	case reflect.Int32:
+		return setIntField(val, 32, structField)
+	case reflect.Int64:
+		return setIntField(val, 64, structField)
+	case reflect.Uint:
+		return setUintField(val, 0, structField)
+	case reflect.Uint8:
+		return setUintField(val, 8, structField)
+	case reflect.Uint16:
+		return setUintField(val, 16, structField)
+	case reflect.Uint32:
+		return setUintField(val, 32, structField)
+	case reflect.Uint64:
+		return setUintField(val, 64, structField)
+	case reflect.Bool:
+		return setBoolField(val, structField)
+	case reflect.Float32:
+		return setFloatField(val, 32, structField)
+	case reflect.Float64:
+		return setFloatField(val, 64, structField)
+	case reflect.String:
+		structField.SetString(val)
+	default:
+		return errors.New("unknown type")
+	}
+	return nil
+}
+
+func unmarshalField(valueKind reflect.Kind, val string, field reflect.Value) (bool, error) {
+	switch valueKind {
+	case reflect.Ptr:
+		return unmarshalFieldPtr(val, field)
+	default:
+		return unmarshalFieldNonPtr(val, field)
+	}
+}
+
+// bindUnmarshaler attempts to unmarshal a reflect.Value into a BindUnmarshaler
+func bindUnmarshaler(field reflect.Value) (BindUnmarshaler, bool) {
+	ptr := reflect.New(field.Type())
+	if ptr.CanInterface() {
+		iface := ptr.Interface()
+		if unmarshaler, ok := iface.(BindUnmarshaler); ok {
+			return unmarshaler, ok
+		}
+	}
+	return nil, false
+}
+
+func unmarshalFieldNonPtr(value string, field reflect.Value) (bool, error) {
+	if unmarshaler, ok := bindUnmarshaler(field); ok {
+		err := unmarshaler.UnmarshalParam(value)
+		field.Set(reflect.ValueOf(unmarshaler).Elem())
+		return true, err
+	}
+	return false, nil
+}
+
+func unmarshalFieldPtr(value string, field reflect.Value) (bool, error) {
+	if field.IsNil() {
+		// Initialize the pointer to a nil value
+		field.Set(reflect.New(field.Type().Elem()))
+	}
+	return unmarshalFieldNonPtr(value, field.Elem())
+}
+
+func setIntField(value string, bitSize int, field reflect.Value) error {
+	if value == "" {
+		value = "0"
+	}
+	intVal, err := strconv.ParseInt(value, 10, bitSize)
+	if err == nil {
+		field.SetInt(intVal)
+	}
+	return err
+}
+
+func setUintField(value string, bitSize int, field reflect.Value) error {
+	if value == "" {
+		value = "0"
+	}
+	uintVal, err := strconv.ParseUint(value, 10, bitSize)
+	if err == nil {
+		field.SetUint(uintVal)
+	}
+	return err
+}
+
+func setBoolField(value string, field reflect.Value) error {
+	if value == "" {
+		value = "false"
+	}
+	boolVal, err := strconv.ParseBool(value)
+	if err == nil {
+		field.SetBool(boolVal)
+	}
+	return err
+}
+
+func setFloatField(value string, bitSize int, field reflect.Value) error {
+	if value == "" {
+		value = "0.0"
+	}
+	floatVal, err := strconv.ParseFloat(value, bitSize)
+	if err == nil {
+		field.SetFloat(floatVal)
+	}
+	return err
+}

+ 576 - 0
vendor/github.com/labstack/echo/context.go

@@ -0,0 +1,576 @@
+package echo
+
+import (
+	"bytes"
+	"encoding/json"
+	"encoding/xml"
+	"fmt"
+	"io"
+	"mime/multipart"
+	"net"
+	"net/http"
+	"net/url"
+	"os"
+	"path/filepath"
+	"strings"
+)
+
+type (
+	// Context represents the context of the current HTTP request. It holds request and
+	// response objects, path, path parameters, data and registered handler.
+	Context interface {
+		// Request returns `*http.Request`.
+		Request() *http.Request
+
+		// SetRequest sets `*http.Request`.
+		SetRequest(r *http.Request)
+
+		// Response returns `*Response`.
+		Response() *Response
+
+		// IsTLS returns true if HTTP connection is TLS otherwise false.
+		IsTLS() bool
+
+		// IsWebSocket returns true if HTTP connection is WebSocket otherwise false.
+		IsWebSocket() bool
+
+		// Scheme returns the HTTP protocol scheme, `http` or `https`.
+		Scheme() string
+
+		// RealIP returns the client's network address based on `X-Forwarded-For`
+		// or `X-Real-IP` request header.
+		RealIP() string
+
+		// Path returns the registered path for the handler.
+		Path() string
+
+		// SetPath sets the registered path for the handler.
+		SetPath(p string)
+
+		// Param returns path parameter by name.
+		Param(name string) string
+
+		// ParamNames returns path parameter names.
+		ParamNames() []string
+
+		// SetParamNames sets path parameter names.
+		SetParamNames(names ...string)
+
+		// ParamValues returns path parameter values.
+		ParamValues() []string
+
+		// SetParamValues sets path parameter values.
+		SetParamValues(values ...string)
+
+		// QueryParam returns the query param for the provided name.
+		QueryParam(name string) string
+
+		// QueryParams returns the query parameters as `url.Values`.
+		QueryParams() url.Values
+
+		// QueryString returns the URL query string.
+		QueryString() string
+
+		// FormValue returns the form field value for the provided name.
+		FormValue(name string) string
+
+		// FormParams returns the form parameters as `url.Values`.
+		FormParams() (url.Values, error)
+
+		// FormFile returns the multipart form file for the provided name.
+		FormFile(name string) (*multipart.FileHeader, error)
+
+		// MultipartForm returns the multipart form.
+		MultipartForm() (*multipart.Form, error)
+
+		// Cookie returns the named cookie provided in the request.
+		Cookie(name string) (*http.Cookie, error)
+
+		// SetCookie adds a `Set-Cookie` header in HTTP response.
+		SetCookie(cookie *http.Cookie)
+
+		// Cookies returns the HTTP cookies sent with the request.
+		Cookies() []*http.Cookie
+
+		// Get retrieves data from the context.
+		Get(key string) interface{}
+
+		// Set saves data in the context.
+		Set(key string, val interface{})
+
+		// Bind binds the request body into provided type `i`. The default binder
+		// does it based on Content-Type header.
+		Bind(i interface{}) error
+
+		// Validate validates provided `i`. It is usually called after `Context#Bind()`.
+		// Validator must be registered using `Echo#Validator`.
+		Validate(i interface{}) error
+
+		// Render renders a template with data and sends a text/html response with status
+		// code. Renderer must be registered using `Echo.Renderer`.
+		Render(code int, name string, data interface{}) error
+
+		// HTML sends an HTTP response with status code.
+		HTML(code int, html string) error
+
+		// HTMLBlob sends an HTTP blob response with status code.
+		HTMLBlob(code int, b []byte) error
+
+		// String sends a string response with status code.
+		String(code int, s string) error
+
+		// JSON sends a JSON response with status code.
+		JSON(code int, i interface{}) error
+
+		// JSONPretty sends a pretty-print JSON with status code.
+		JSONPretty(code int, i interface{}, indent string) error
+
+		// JSONBlob sends a JSON blob response with status code.
+		JSONBlob(code int, b []byte) error
+
+		// JSONP sends a JSONP response with status code. It uses `callback` to construct
+		// the JSONP payload.
+		JSONP(code int, callback string, i interface{}) error
+
+		// JSONPBlob sends a JSONP blob response with status code. It uses `callback`
+		// to construct the JSONP payload.
+		JSONPBlob(code int, callback string, b []byte) error
+
+		// XML sends an XML response with status code.
+		XML(code int, i interface{}) error
+
+		// XMLPretty sends a pretty-print XML with status code.
+		XMLPretty(code int, i interface{}, indent string) error
+
+		// XMLBlob sends an XML blob response with status code.
+		XMLBlob(code int, b []byte) error
+
+		// Blob sends a blob response with status code and content type.
+		Blob(code int, contentType string, b []byte) error
+
+		// Stream sends a streaming response with status code and content type.
+		Stream(code int, contentType string, r io.Reader) error
+
+		// File sends a response with the content of the file.
+		File(file string) error
+
+		// Attachment sends a response as attachment, prompting client to save the
+		// file.
+		Attachment(file string, name string) error
+
+		// Inline sends a response as inline, opening the file in the browser.
+		Inline(file string, name string) error
+
+		// NoContent sends a response with no body and a status code.
+		NoContent(code int) error
+
+		// Redirect redirects the request to a provided URL with status code.
+		Redirect(code int, url string) error
+
+		// Error invokes the registered HTTP error handler. Generally used by middleware.
+		Error(err error)
+
+		// Handler returns the matched handler by router.
+		Handler() HandlerFunc
+
+		// SetHandler sets the matched handler by router.
+		SetHandler(h HandlerFunc)
+
+		// Logger returns the `Logger` instance.
+		Logger() Logger
+
+		// Echo returns the `Echo` instance.
+		Echo() *Echo
+
+		// Reset resets the context after request completes. It must be called along
+		// with `Echo#AcquireContext()` and `Echo#ReleaseContext()`.
+		// See `Echo#ServeHTTP()`
+		Reset(r *http.Request, w http.ResponseWriter)
+	}
+
+	context struct {
+		request  *http.Request
+		response *Response
+		path     string
+		pnames   []string
+		pvalues  []string
+		query    url.Values
+		handler  HandlerFunc
+		store    Map
+		echo     *Echo
+	}
+)
+
+const (
+	defaultMemory = 32 << 20 // 32 MB
+	indexPage     = "index.html"
+)
+
+func (c *context) writeContentType(value string) {
+	header := c.Response().Header()
+	if header.Get(HeaderContentType) == "" {
+		header.Set(HeaderContentType, value)
+	}
+}
+
+func (c *context) Request() *http.Request {
+	return c.request
+}
+
+func (c *context) SetRequest(r *http.Request) {
+	c.request = r
+}
+
+func (c *context) Response() *Response {
+	return c.response
+}
+
+func (c *context) IsTLS() bool {
+	return c.request.TLS != nil
+}
+
+func (c *context) IsWebSocket() bool {
+	upgrade := c.request.Header.Get(HeaderUpgrade)
+	return upgrade == "websocket" || upgrade == "Websocket"
+}
+
+func (c *context) Scheme() string {
+	// Can't use `r.Request.URL.Scheme`
+	// See: https://groups.google.com/forum/#!topic/golang-nuts/pMUkBlQBDF0
+	if c.IsTLS() {
+		return "https"
+	}
+	if scheme := c.request.Header.Get(HeaderXForwardedProto); scheme != "" {
+		return scheme
+	}
+	if scheme := c.request.Header.Get(HeaderXForwardedProtocol); scheme != "" {
+		return scheme
+	}
+	if ssl := c.request.Header.Get(HeaderXForwardedSsl); ssl == "on" {
+		return "https"
+	}
+	if scheme := c.request.Header.Get(HeaderXUrlScheme); scheme != "" {
+		return scheme
+	}
+	return "http"
+}
+
+func (c *context) RealIP() string {
+	ra := c.request.RemoteAddr
+	if ip := c.request.Header.Get(HeaderXForwardedFor); ip != "" {
+		ra = strings.Split(ip, ", ")[0]
+	} else if ip := c.request.Header.Get(HeaderXRealIP); ip != "" {
+		ra = ip
+	} else {
+		ra, _, _ = net.SplitHostPort(ra)
+	}
+	return ra
+}
+
+func (c *context) Path() string {
+	return c.path
+}
+
+func (c *context) SetPath(p string) {
+	c.path = p
+}
+
+func (c *context) Param(name string) string {
+	for i, n := range c.pnames {
+		if i < len(c.pvalues) {
+			if n == name {
+				return c.pvalues[i]
+			}
+		}
+	}
+	return ""
+}
+
+func (c *context) ParamNames() []string {
+	return c.pnames
+}
+
+func (c *context) SetParamNames(names ...string) {
+	c.pnames = names
+}
+
+func (c *context) ParamValues() []string {
+	return c.pvalues[:len(c.pnames)]
+}
+
+func (c *context) SetParamValues(values ...string) {
+	c.pvalues = values
+}
+
+func (c *context) QueryParam(name string) string {
+	if c.query == nil {
+		c.query = c.request.URL.Query()
+	}
+	return c.query.Get(name)
+}
+
+func (c *context) QueryParams() url.Values {
+	if c.query == nil {
+		c.query = c.request.URL.Query()
+	}
+	return c.query
+}
+
+func (c *context) QueryString() string {
+	return c.request.URL.RawQuery
+}
+
+func (c *context) FormValue(name string) string {
+	return c.request.FormValue(name)
+}
+
+func (c *context) FormParams() (url.Values, error) {
+	if strings.HasPrefix(c.request.Header.Get(HeaderContentType), MIMEMultipartForm) {
+		if err := c.request.ParseMultipartForm(defaultMemory); err != nil {
+			return nil, err
+		}
+	} else {
+		if err := c.request.ParseForm(); err != nil {
+			return nil, err
+		}
+	}
+	return c.request.Form, nil
+}
+
+func (c *context) FormFile(name string) (*multipart.FileHeader, error) {
+	_, fh, err := c.request.FormFile(name)
+	return fh, err
+}
+
+func (c *context) MultipartForm() (*multipart.Form, error) {
+	err := c.request.ParseMultipartForm(defaultMemory)
+	return c.request.MultipartForm, err
+}
+
+func (c *context) Cookie(name string) (*http.Cookie, error) {
+	return c.request.Cookie(name)
+}
+
+func (c *context) SetCookie(cookie *http.Cookie) {
+	http.SetCookie(c.Response(), cookie)
+}
+
+func (c *context) Cookies() []*http.Cookie {
+	return c.request.Cookies()
+}
+
+func (c *context) Get(key string) interface{} {
+	return c.store[key]
+}
+
+func (c *context) Set(key string, val interface{}) {
+	if c.store == nil {
+		c.store = make(Map)
+	}
+	c.store[key] = val
+}
+
+func (c *context) Bind(i interface{}) error {
+	return c.echo.Binder.Bind(i, c)
+}
+
+func (c *context) Validate(i interface{}) error {
+	if c.echo.Validator == nil {
+		return ErrValidatorNotRegistered
+	}
+	return c.echo.Validator.Validate(i)
+}
+
+func (c *context) Render(code int, name string, data interface{}) (err error) {
+	if c.echo.Renderer == nil {
+		return ErrRendererNotRegistered
+	}
+	buf := new(bytes.Buffer)
+	if err = c.echo.Renderer.Render(buf, name, data, c); err != nil {
+		return
+	}
+	return c.HTMLBlob(code, buf.Bytes())
+}
+
+func (c *context) HTML(code int, html string) (err error) {
+	return c.HTMLBlob(code, []byte(html))
+}
+
+func (c *context) HTMLBlob(code int, b []byte) (err error) {
+	return c.Blob(code, MIMETextHTMLCharsetUTF8, b)
+}
+
+func (c *context) String(code int, s string) (err error) {
+	return c.Blob(code, MIMETextPlainCharsetUTF8, []byte(s))
+}
+
+func (c *context) JSON(code int, i interface{}) (err error) {
+	_, pretty := c.QueryParams()["pretty"]
+	if c.echo.Debug || pretty {
+		return c.JSONPretty(code, i, "  ")
+	}
+	b, err := json.Marshal(i)
+	if err != nil {
+		return
+	}
+	return c.JSONBlob(code, b)
+}
+
+func (c *context) JSONPretty(code int, i interface{}, indent string) (err error) {
+	b, err := json.MarshalIndent(i, "", indent)
+	if err != nil {
+		return
+	}
+	return c.JSONBlob(code, b)
+}
+
+func (c *context) JSONBlob(code int, b []byte) (err error) {
+	return c.Blob(code, MIMEApplicationJSONCharsetUTF8, b)
+}
+
+func (c *context) JSONP(code int, callback string, i interface{}) (err error) {
+	b, err := json.Marshal(i)
+	if err != nil {
+		return
+	}
+	return c.JSONPBlob(code, callback, b)
+}
+
+func (c *context) JSONPBlob(code int, callback string, b []byte) (err error) {
+	c.writeContentType(MIMEApplicationJavaScriptCharsetUTF8)
+	c.response.WriteHeader(code)
+	if _, err = c.response.Write([]byte(callback + "(")); err != nil {
+		return
+	}
+	if _, err = c.response.Write(b); err != nil {
+		return
+	}
+	_, err = c.response.Write([]byte(");"))
+	return
+}
+
+func (c *context) XML(code int, i interface{}) (err error) {
+	_, pretty := c.QueryParams()["pretty"]
+	if c.echo.Debug || pretty {
+		return c.XMLPretty(code, i, "  ")
+	}
+	b, err := xml.Marshal(i)
+	if err != nil {
+		return
+	}
+	return c.XMLBlob(code, b)
+}
+
+func (c *context) XMLPretty(code int, i interface{}, indent string) (err error) {
+	b, err := xml.MarshalIndent(i, "", indent)
+	if err != nil {
+		return
+	}
+	return c.XMLBlob(code, b)
+}
+
+func (c *context) XMLBlob(code int, b []byte) (err error) {
+	c.writeContentType(MIMEApplicationXMLCharsetUTF8)
+	c.response.WriteHeader(code)
+	if _, err = c.response.Write([]byte(xml.Header)); err != nil {
+		return
+	}
+	_, err = c.response.Write(b)
+	return
+}
+
+func (c *context) Blob(code int, contentType string, b []byte) (err error) {
+	c.writeContentType(contentType)
+	c.response.WriteHeader(code)
+	_, err = c.response.Write(b)
+	return
+}
+
+func (c *context) Stream(code int, contentType string, r io.Reader) (err error) {
+	c.writeContentType(contentType)
+	c.response.WriteHeader(code)
+	_, err = io.Copy(c.response, r)
+	return
+}
+
+func (c *context) File(file string) (err error) {
+	f, err := os.Open(file)
+	if err != nil {
+		return NotFoundHandler(c)
+	}
+	defer f.Close()
+
+	fi, _ := f.Stat()
+	if fi.IsDir() {
+		file = filepath.Join(file, indexPage)
+		f, err = os.Open(file)
+		if err != nil {
+			return NotFoundHandler(c)
+		}
+		defer f.Close()
+		if fi, err = f.Stat(); err != nil {
+			return
+		}
+	}
+	http.ServeContent(c.Response(), c.Request(), fi.Name(), fi.ModTime(), f)
+	return
+}
+
+func (c *context) Attachment(file, name string) error {
+	return c.contentDisposition(file, name, "attachment")
+}
+
+func (c *context) Inline(file, name string) error {
+	return c.contentDisposition(file, name, "inline")
+}
+
+func (c *context) contentDisposition(file, name, dispositionType string) error {
+	c.response.Header().Set(HeaderContentDisposition, fmt.Sprintf("%s; filename=%q", dispositionType, name))
+	return c.File(file)
+}
+
+func (c *context) NoContent(code int) error {
+	c.response.WriteHeader(code)
+	return nil
+}
+
+func (c *context) Redirect(code int, url string) error {
+	if code < 300 || code > 308 {
+		return ErrInvalidRedirectCode
+	}
+	c.response.Header().Set(HeaderLocation, url)
+	c.response.WriteHeader(code)
+	return nil
+}
+
+func (c *context) Error(err error) {
+	c.echo.HTTPErrorHandler(err, c)
+}
+
+func (c *context) Echo() *Echo {
+	return c.echo
+}
+
+func (c *context) Handler() HandlerFunc {
+	return c.handler
+}
+
+func (c *context) SetHandler(h HandlerFunc) {
+	c.handler = h
+}
+
+func (c *context) Logger() Logger {
+	return c.echo.Logger
+}
+
+func (c *context) Reset(r *http.Request, w http.ResponseWriter) {
+	c.request = r
+	c.response.reset(w)
+	c.query = nil
+	c.handler = NotFoundHandler
+	c.store = nil
+	c.path = ""
+	c.pnames = nil
+	// NOTE: Don't reset because it has to have length c.echo.maxParam at all times
+	// c.pvalues = nil
+}

+ 770 - 0
vendor/github.com/labstack/echo/echo.go

@@ -0,0 +1,770 @@
+/*
+Package echo implements high performance, minimalist Go web framework.
+
+Example:
+
+  package main
+
+  import (
+    "net/http"
+
+    "github.com/labstack/echo"
+    "github.com/labstack/echo/middleware"
+  )
+
+  // Handler
+  func hello(c echo.Context) error {
+    return c.String(http.StatusOK, "Hello, World!")
+  }
+
+  func main() {
+    // Echo instance
+    e := echo.New()
+
+    // Middleware
+    e.Use(middleware.Logger())
+    e.Use(middleware.Recover())
+
+    // Routes
+    e.GET("/", hello)
+
+    // Start server
+    e.Logger.Fatal(e.Start(":1323"))
+  }
+
+Learn more at https://echo.labstack.com
+*/
+package echo
+
+import (
+	"bytes"
+	stdContext "context"
+	"crypto/tls"
+	"errors"
+	"fmt"
+	"io"
+	stdLog "log"
+	"net"
+	"net/http"
+	"net/url"
+	"path"
+	"path/filepath"
+	"reflect"
+	"runtime"
+	"sync"
+	"time"
+
+	"github.com/labstack/gommon/color"
+	"github.com/labstack/gommon/log"
+	"golang.org/x/crypto/acme/autocert"
+)
+
+type (
+	// Echo is the top-level framework instance.
+	Echo struct {
+		stdLogger        *stdLog.Logger
+		colorer          *color.Color
+		premiddleware    []MiddlewareFunc
+		middleware       []MiddlewareFunc
+		maxParam         *int
+		router           *Router
+		notFoundHandler  HandlerFunc
+		pool             sync.Pool
+		Server           *http.Server
+		TLSServer        *http.Server
+		Listener         net.Listener
+		TLSListener      net.Listener
+		AutoTLSManager   autocert.Manager
+		DisableHTTP2     bool
+		Debug            bool
+		HideBanner       bool
+		HidePort         bool
+		HTTPErrorHandler HTTPErrorHandler
+		Binder           Binder
+		Validator        Validator
+		Renderer         Renderer
+		Logger           Logger
+	}
+
+	// Route contains a handler and information for matching against requests.
+	Route struct {
+		Method string `json:"method"`
+		Path   string `json:"path"`
+		Name   string `json:"name"`
+	}
+
+	// HTTPError represents an error that occurred while handling a request.
+	HTTPError struct {
+		Code     int
+		Message  interface{}
+		Internal error // Stores the error returned by an external dependency
+	}
+
+	// MiddlewareFunc defines a function to process middleware.
+	MiddlewareFunc func(HandlerFunc) HandlerFunc
+
+	// HandlerFunc defines a function to serve HTTP requests.
+	HandlerFunc func(Context) error
+
+	// HTTPErrorHandler is a centralized HTTP error handler.
+	HTTPErrorHandler func(error, Context)
+
+	// Validator is the interface that wraps the Validate function.
+	Validator interface {
+		Validate(i interface{}) error
+	}
+
+	// Renderer is the interface that wraps the Render function.
+	Renderer interface {
+		Render(io.Writer, string, interface{}, Context) error
+	}
+
+	// Map defines a generic map of type `map[string]interface{}`.
+	Map map[string]interface{}
+
+	// i is the interface for Echo and Group.
+	i interface {
+		GET(string, HandlerFunc, ...MiddlewareFunc) *Route
+	}
+)
+
+// HTTP methods
+const (
+	CONNECT  = "CONNECT"
+	DELETE   = "DELETE"
+	GET      = "GET"
+	HEAD     = "HEAD"
+	OPTIONS  = "OPTIONS"
+	PATCH    = "PATCH"
+	POST     = "POST"
+	PROPFIND = "PROPFIND"
+	PUT      = "PUT"
+	TRACE    = "TRACE"
+)
+
+// MIME types
+const (
+	MIMEApplicationJSON                  = "application/json"
+	MIMEApplicationJSONCharsetUTF8       = MIMEApplicationJSON + "; " + charsetUTF8
+	MIMEApplicationJavaScript            = "application/javascript"
+	MIMEApplicationJavaScriptCharsetUTF8 = MIMEApplicationJavaScript + "; " + charsetUTF8
+	MIMEApplicationXML                   = "application/xml"
+	MIMEApplicationXMLCharsetUTF8        = MIMEApplicationXML + "; " + charsetUTF8
+	MIMETextXML                          = "text/xml"
+	MIMETextXMLCharsetUTF8               = MIMETextXML + "; " + charsetUTF8
+	MIMEApplicationForm                  = "application/x-www-form-urlencoded"
+	MIMEApplicationProtobuf              = "application/protobuf"
+	MIMEApplicationMsgpack               = "application/msgpack"
+	MIMETextHTML                         = "text/html"
+	MIMETextHTMLCharsetUTF8              = MIMETextHTML + "; " + charsetUTF8
+	MIMETextPlain                        = "text/plain"
+	MIMETextPlainCharsetUTF8             = MIMETextPlain + "; " + charsetUTF8
+	MIMEMultipartForm                    = "multipart/form-data"
+	MIMEOctetStream                      = "application/octet-stream"
+)
+
+const (
+	charsetUTF8 = "charset=UTF-8"
+)
+
+// Headers
+const (
+	HeaderAccept              = "Accept"
+	HeaderAcceptEncoding      = "Accept-Encoding"
+	HeaderAllow               = "Allow"
+	HeaderAuthorization       = "Authorization"
+	HeaderContentDisposition  = "Content-Disposition"
+	HeaderContentEncoding     = "Content-Encoding"
+	HeaderContentLength       = "Content-Length"
+	HeaderContentType         = "Content-Type"
+	HeaderCookie              = "Cookie"
+	HeaderSetCookie           = "Set-Cookie"
+	HeaderIfModifiedSince     = "If-Modified-Since"
+	HeaderLastModified        = "Last-Modified"
+	HeaderLocation            = "Location"
+	HeaderUpgrade             = "Upgrade"
+	HeaderVary                = "Vary"
+	HeaderWWWAuthenticate     = "WWW-Authenticate"
+	HeaderXForwardedFor       = "X-Forwarded-For"
+	HeaderXForwardedProto     = "X-Forwarded-Proto"
+	HeaderXForwardedProtocol  = "X-Forwarded-Protocol"
+	HeaderXForwardedSsl       = "X-Forwarded-Ssl"
+	HeaderXUrlScheme          = "X-Url-Scheme"
+	HeaderXHTTPMethodOverride = "X-HTTP-Method-Override"
+	HeaderXRealIP             = "X-Real-IP"
+	HeaderXRequestID          = "X-Request-ID"
+	HeaderXRequestedWith      = "X-Requested-With"
+	HeaderServer              = "Server"
+	HeaderOrigin              = "Origin"
+
+	// Access control
+	HeaderAccessControlRequestMethod    = "Access-Control-Request-Method"
+	HeaderAccessControlRequestHeaders   = "Access-Control-Request-Headers"
+	HeaderAccessControlAllowOrigin      = "Access-Control-Allow-Origin"
+	HeaderAccessControlAllowMethods     = "Access-Control-Allow-Methods"
+	HeaderAccessControlAllowHeaders     = "Access-Control-Allow-Headers"
+	HeaderAccessControlAllowCredentials = "Access-Control-Allow-Credentials"
+	HeaderAccessControlExposeHeaders    = "Access-Control-Expose-Headers"
+	HeaderAccessControlMaxAge           = "Access-Control-Max-Age"
+
+	// Security
+	HeaderStrictTransportSecurity = "Strict-Transport-Security"
+	HeaderXContentTypeOptions     = "X-Content-Type-Options"
+	HeaderXXSSProtection          = "X-XSS-Protection"
+	HeaderXFrameOptions           = "X-Frame-Options"
+	HeaderContentSecurityPolicy   = "Content-Security-Policy"
+	HeaderXCSRFToken              = "X-CSRF-Token"
+)
+
+const (
+	Version = "3.3.6"
+	website = "https://echo.labstack.com"
+	// http://patorjk.com/software/taag/#p=display&f=Small%20Slant&t=Echo
+	banner = `
+   ____    __
+  / __/___/ /  ___
+ / _// __/ _ \/ _ \
+/___/\__/_//_/\___/ %s
+High performance, minimalist Go web framework
+%s
+____________________________________O/_______
+                                    O\
+`
+)
+
+var (
+	methods = [...]string{
+		CONNECT,
+		DELETE,
+		GET,
+		HEAD,
+		OPTIONS,
+		PATCH,
+		POST,
+		PROPFIND,
+		PUT,
+		TRACE,
+	}
+)
+
+// Errors
+var (
+	ErrUnsupportedMediaType        = NewHTTPError(http.StatusUnsupportedMediaType)
+	ErrNotFound                    = NewHTTPError(http.StatusNotFound)
+	ErrUnauthorized                = NewHTTPError(http.StatusUnauthorized)
+	ErrForbidden                   = NewHTTPError(http.StatusForbidden)
+	ErrMethodNotAllowed            = NewHTTPError(http.StatusMethodNotAllowed)
+	ErrStatusRequestEntityTooLarge = NewHTTPError(http.StatusRequestEntityTooLarge)
+	ErrValidatorNotRegistered      = errors.New("validator not registered")
+	ErrRendererNotRegistered       = errors.New("renderer not registered")
+	ErrInvalidRedirectCode         = errors.New("invalid redirect status code")
+	ErrCookieNotFound              = errors.New("cookie not found")
+)
+
+// Error handlers
+var (
+	NotFoundHandler = func(c Context) error {
+		return ErrNotFound
+	}
+
+	MethodNotAllowedHandler = func(c Context) error {
+		return ErrMethodNotAllowed
+	}
+)
+
+// New creates an instance of Echo.
+func New() (e *Echo) {
+	e = &Echo{
+		Server:    new(http.Server),
+		TLSServer: new(http.Server),
+		AutoTLSManager: autocert.Manager{
+			Prompt: autocert.AcceptTOS,
+		},
+		Logger:   log.New("echo"),
+		colorer:  color.New(),
+		maxParam: new(int),
+	}
+	e.Server.Handler = e
+	e.TLSServer.Handler = e
+	e.HTTPErrorHandler = e.DefaultHTTPErrorHandler
+	e.Binder = &DefaultBinder{}
+	e.Logger.SetLevel(log.ERROR)
+	e.stdLogger = stdLog.New(e.Logger.Output(), e.Logger.Prefix()+": ", 0)
+	e.pool.New = func() interface{} {
+		return e.NewContext(nil, nil)
+	}
+	e.router = NewRouter(e)
+	return
+}
+
+// NewContext returns a Context instance.
+func (e *Echo) NewContext(r *http.Request, w http.ResponseWriter) Context {
+	return &context{
+		request:  r,
+		response: NewResponse(w, e),
+		store:    make(Map),
+		echo:     e,
+		pvalues:  make([]string, *e.maxParam),
+		handler:  NotFoundHandler,
+	}
+}
+
+// Router returns router.
+func (e *Echo) Router() *Router {
+	return e.router
+}
+
+// DefaultHTTPErrorHandler is the default HTTP error handler. It sends a JSON response
+// with status code.
+func (e *Echo) DefaultHTTPErrorHandler(err error, c Context) {
+	var (
+		code = http.StatusInternalServerError
+		msg  interface{}
+	)
+
+	if he, ok := err.(*HTTPError); ok {
+		code = he.Code
+		msg = he.Message
+		if he.Internal != nil {
+			err = fmt.Errorf("%v, %v", err, he.Internal)
+		}
+	} else if e.Debug {
+		msg = err.Error()
+	} else {
+		msg = http.StatusText(code)
+	}
+	if _, ok := msg.(string); ok {
+		msg = Map{"message": msg}
+	}
+
+	// Send response
+	if !c.Response().Committed {
+		if c.Request().Method == HEAD { // Issue #608
+			err = c.NoContent(code)
+		} else {
+			err = c.JSON(code, msg)
+		}
+		if err != nil {
+			e.Logger.Error(err)
+		}
+	}
+}
+
+// Pre adds middleware to the chain which is run before router.
+func (e *Echo) Pre(middleware ...MiddlewareFunc) {
+	e.premiddleware = append(e.premiddleware, middleware...)
+}
+
+// Use adds middleware to the chain which is run after router.
+func (e *Echo) Use(middleware ...MiddlewareFunc) {
+	e.middleware = append(e.middleware, middleware...)
+}
+
+// CONNECT registers a new CONNECT route for a path with matching handler in the
+// router with optional route-level middleware.
+func (e *Echo) CONNECT(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+	return e.Add(CONNECT, path, h, m...)
+}
+
+// DELETE registers a new DELETE route for a path with matching handler in the router
+// with optional route-level middleware.
+func (e *Echo) DELETE(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+	return e.Add(DELETE, path, h, m...)
+}
+
+// GET registers a new GET route for a path with matching handler in the router
+// with optional route-level middleware.
+func (e *Echo) GET(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+	return e.Add(GET, path, h, m...)
+}
+
+// HEAD registers a new HEAD route for a path with matching handler in the
+// router with optional route-level middleware.
+func (e *Echo) HEAD(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+	return e.Add(HEAD, path, h, m...)
+}
+
+// OPTIONS registers a new OPTIONS route for a path with matching handler in the
+// router with optional route-level middleware.
+func (e *Echo) OPTIONS(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+	return e.Add(OPTIONS, path, h, m...)
+}
+
+// PATCH registers a new PATCH route for a path with matching handler in the
+// router with optional route-level middleware.
+func (e *Echo) PATCH(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+	return e.Add(PATCH, path, h, m...)
+}
+
+// POST registers a new POST route for a path with matching handler in the
+// router with optional route-level middleware.
+func (e *Echo) POST(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+	return e.Add(POST, path, h, m...)
+}
+
+// PUT registers a new PUT route for a path with matching handler in the
+// router with optional route-level middleware.
+func (e *Echo) PUT(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+	return e.Add(PUT, path, h, m...)
+}
+
+// TRACE registers a new TRACE route for a path with matching handler in the
+// router with optional route-level middleware.
+func (e *Echo) TRACE(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+	return e.Add(TRACE, path, h, m...)
+}
+
+// Any registers a new route for all HTTP methods and path with matching handler
+// in the router with optional route-level middleware.
+func (e *Echo) Any(path string, handler HandlerFunc, middleware ...MiddlewareFunc) []*Route {
+	routes := make([]*Route, len(methods))
+	for i, m := range methods {
+		routes[i] = e.Add(m, path, handler, middleware...)
+	}
+	return routes
+}
+
+// Match registers a new route for multiple HTTP methods and path with matching
+// handler in the router with optional route-level middleware.
+func (e *Echo) Match(methods []string, path string, handler HandlerFunc, middleware ...MiddlewareFunc) []*Route {
+	routes := make([]*Route, len(methods))
+	for i, m := range methods {
+		routes[i] = e.Add(m, path, handler, middleware...)
+	}
+	return routes
+}
+
+// Static registers a new route with path prefix to serve static files from the
+// provided root directory.
+func (e *Echo) Static(prefix, root string) *Route {
+	if root == "" {
+		root = "." // For security we want to restrict to CWD.
+	}
+	return static(e, prefix, root)
+}
+
+func static(i i, prefix, root string) *Route {
+	h := func(c Context) error {
+		p, err := url.PathUnescape(c.Param("*"))
+		if err != nil {
+			return err
+		}
+		name := filepath.Join(root, path.Clean("/"+p)) // "/"+ for security
+		return c.File(name)
+	}
+	i.GET(prefix, h)
+	if prefix == "/" {
+		return i.GET(prefix+"*", h)
+	}
+
+	return i.GET(prefix+"/*", h)
+}
+
+// File registers a new route with path to serve a static file with optional route-level middleware.
+func (e *Echo) File(path, file string, m ...MiddlewareFunc) *Route {
+	return e.GET(path, func(c Context) error {
+		return c.File(file)
+	}, m...)
+}
+
+// Add registers a new route for an HTTP method and path with matching handler
+// in the router with optional route-level middleware.
+func (e *Echo) Add(method, path string, handler HandlerFunc, middleware ...MiddlewareFunc) *Route {
+	name := handlerName(handler)
+	e.router.Add(method, path, func(c Context) error {
+		h := handler
+		// Chain middleware
+		for i := len(middleware) - 1; i >= 0; i-- {
+			h = middleware[i](h)
+		}
+		return h(c)
+	})
+	r := &Route{
+		Method: method,
+		Path:   path,
+		Name:   name,
+	}
+	e.router.routes[method+path] = r
+	return r
+}
+
+// Group creates a new router group with prefix and optional group-level middleware.
+func (e *Echo) Group(prefix string, m ...MiddlewareFunc) (g *Group) {
+	g = &Group{prefix: prefix, echo: e}
+	g.Use(m...)
+	return
+}
+
+// URI generates a URI from handler.
+func (e *Echo) URI(handler HandlerFunc, params ...interface{}) string {
+	name := handlerName(handler)
+	return e.Reverse(name, params...)
+}
+
+// URL is an alias for `URI` function.
+func (e *Echo) URL(h HandlerFunc, params ...interface{}) string {
+	return e.URI(h, params...)
+}
+
+// Reverse generates an URL from route name and provided parameters.
+func (e *Echo) Reverse(name string, params ...interface{}) string {
+	uri := new(bytes.Buffer)
+	ln := len(params)
+	n := 0
+	for _, r := range e.router.routes {
+		if r.Name == name {
+			for i, l := 0, len(r.Path); i < l; i++ {
+				if r.Path[i] == ':' && n < ln {
+					for ; i < l && r.Path[i] != '/'; i++ {
+					}
+					uri.WriteString(fmt.Sprintf("%v", params[n]))
+					n++
+				}
+				if i < l {
+					uri.WriteByte(r.Path[i])
+				}
+			}
+			break
+		}
+	}
+	return uri.String()
+}
+
+// Routes returns the registered routes.
+func (e *Echo) Routes() []*Route {
+	routes := make([]*Route, 0, len(e.router.routes))
+	for _, v := range e.router.routes {
+		routes = append(routes, v)
+	}
+	return routes
+}
+
+// AcquireContext returns an empty `Context` instance from the pool.
+// You must return the context by calling `ReleaseContext()`.
+func (e *Echo) AcquireContext() Context {
+	return e.pool.Get().(Context)
+}
+
+// ReleaseContext returns the `Context` instance back to the pool.
+// You must call it after `AcquireContext()`.
+func (e *Echo) ReleaseContext(c Context) {
+	e.pool.Put(c)
+}
+
+// ServeHTTP implements `http.Handler` interface, which serves HTTP requests.
+func (e *Echo) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	// Acquire context
+	c := e.pool.Get().(*context)
+	c.Reset(r, w)
+
+	h := NotFoundHandler
+
+	if e.premiddleware == nil {
+		e.router.Find(r.Method, getPath(r), c)
+		h = c.Handler()
+		for i := len(e.middleware) - 1; i >= 0; i-- {
+			h = e.middleware[i](h)
+		}
+	} else {
+		h = func(c Context) error {
+			e.router.Find(r.Method, getPath(r), c)
+			h := c.Handler()
+			for i := len(e.middleware) - 1; i >= 0; i-- {
+				h = e.middleware[i](h)
+			}
+			return h(c)
+		}
+		for i := len(e.premiddleware) - 1; i >= 0; i-- {
+			h = e.premiddleware[i](h)
+		}
+	}
+
+	// Execute chain
+	if err := h(c); err != nil {
+		e.HTTPErrorHandler(err, c)
+	}
+
+	// Release context
+	e.pool.Put(c)
+}
+
+// Start starts an HTTP server.
+func (e *Echo) Start(address string) error {
+	e.Server.Addr = address
+	return e.StartServer(e.Server)
+}
+
+// StartTLS starts an HTTPS server.
+func (e *Echo) StartTLS(address string, certFile, keyFile string) (err error) {
+	if certFile == "" || keyFile == "" {
+		return errors.New("invalid tls configuration")
+	}
+	s := e.TLSServer
+	s.TLSConfig = new(tls.Config)
+	s.TLSConfig.Certificates = make([]tls.Certificate, 1)
+	s.TLSConfig.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
+	if err != nil {
+		return
+	}
+	return e.startTLS(address)
+}
+
+// StartAutoTLS starts an HTTPS server using certificates automatically installed from https://letsencrypt.org.
+func (e *Echo) StartAutoTLS(address string) error {
+	if e.Listener == nil {
+		go http.ListenAndServe(":http", e.AutoTLSManager.HTTPHandler(nil))
+	}
+
+	s := e.TLSServer
+	s.TLSConfig = new(tls.Config)
+	s.TLSConfig.GetCertificate = e.AutoTLSManager.GetCertificate
+	return e.startTLS(address)
+}
+
+func (e *Echo) startTLS(address string) error {
+	s := e.TLSServer
+	s.Addr = address
+	if !e.DisableHTTP2 {
+		s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, "h2")
+	}
+	return e.StartServer(e.TLSServer)
+}
+
+// StartServer starts a custom http server.
+func (e *Echo) StartServer(s *http.Server) (err error) {
+	// Setup
+	e.colorer.SetOutput(e.Logger.Output())
+	s.ErrorLog = e.stdLogger
+	s.Handler = e
+	if e.Debug {
+		e.Logger.SetLevel(log.DEBUG)
+	}
+
+	if !e.HideBanner {
+		e.colorer.Printf(banner, e.colorer.Red("v"+Version), e.colorer.Blue(website))
+	}
+
+	if s.TLSConfig == nil {
+		if e.Listener == nil {
+			e.Listener, err = newListener(s.Addr)
+			if err != nil {
+				return err
+			}
+		}
+		if !e.HidePort {
+			e.colorer.Printf("⇨ http server started on %s\n", e.colorer.Green(e.Listener.Addr()))
+		}
+		return s.Serve(e.Listener)
+	}
+	if e.TLSListener == nil {
+		l, err := newListener(s.Addr)
+		if err != nil {
+			return err
+		}
+		e.TLSListener = tls.NewListener(l, s.TLSConfig)
+	}
+	if !e.HidePort {
+		e.colorer.Printf("⇨ https server started on %s\n", e.colorer.Green(e.TLSListener.Addr()))
+	}
+	return s.Serve(e.TLSListener)
+}
+
+// Close immediately stops the server.
+// It internally calls `http.Server#Close()`.
+func (e *Echo) Close() error {
+	if err := e.TLSServer.Close(); err != nil {
+		return err
+	}
+	return e.Server.Close()
+}
+
+// Shutdown stops server the gracefully.
+// It internally calls `http.Server#Shutdown()`.
+func (e *Echo) Shutdown(ctx stdContext.Context) error {
+	if err := e.TLSServer.Shutdown(ctx); err != nil {
+		return err
+	}
+	return e.Server.Shutdown(ctx)
+}
+
+// NewHTTPError creates a new HTTPError instance.
+func NewHTTPError(code int, message ...interface{}) *HTTPError {
+	he := &HTTPError{Code: code, Message: http.StatusText(code)}
+	if len(message) > 0 {
+		he.Message = message[0]
+	}
+	return he
+}
+
+// Error makes it compatible with `error` interface.
+func (he *HTTPError) Error() string {
+	return fmt.Sprintf("code=%d, message=%v", he.Code, he.Message)
+}
+
+// WrapHandler wraps `http.Handler` into `echo.HandlerFunc`.
+func WrapHandler(h http.Handler) HandlerFunc {
+	return func(c Context) error {
+		h.ServeHTTP(c.Response(), c.Request())
+		return nil
+	}
+}
+
+// WrapMiddleware wraps `func(http.Handler) http.Handler` into `echo.MiddlewareFunc`
+func WrapMiddleware(m func(http.Handler) http.Handler) MiddlewareFunc {
+	return func(next HandlerFunc) HandlerFunc {
+		return func(c Context) (err error) {
+			m(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+				c.SetRequest(r)
+				err = next(c)
+			})).ServeHTTP(c.Response(), c.Request())
+			return
+		}
+	}
+}
+
+func getPath(r *http.Request) string {
+	path := r.URL.RawPath
+	if path == "" {
+		path = r.URL.Path
+	}
+	return path
+}
+
+func handlerName(h HandlerFunc) string {
+	t := reflect.ValueOf(h).Type()
+	if t.Kind() == reflect.Func {
+		return runtime.FuncForPC(reflect.ValueOf(h).Pointer()).Name()
+	}
+	return t.String()
+}
+
+// // PathUnescape is wraps `url.PathUnescape`
+// func PathUnescape(s string) (string, error) {
+// 	return url.PathUnescape(s)
+// }
+
+// tcpKeepAliveListener sets TCP keep-alive timeouts on accepted
+// connections. It's used by ListenAndServe and ListenAndServeTLS so
+// dead TCP connections (e.g. closing laptop mid-download) eventually
+// go away.
+type tcpKeepAliveListener struct {
+	*net.TCPListener
+}
+
+func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
+	tc, err := ln.AcceptTCP()
+	if err != nil {
+		return
+	}
+	tc.SetKeepAlive(true)
+	tc.SetKeepAlivePeriod(3 * time.Minute)
+	return tc, nil
+}
+
+func newListener(address string) (*tcpKeepAliveListener, error) {
+	l, err := net.Listen("tcp", address)
+	if err != nil {
+		return nil, err
+	}
+	return &tcpKeepAliveListener{l.(*net.TCPListener)}, nil
+}

+ 15 - 0
vendor/github.com/labstack/echo/go.mod

@@ -0,0 +1,15 @@
+module github.com/labstack/echo
+
+require (
+	github.com/davecgh/go-spew v1.1.0 // indirect
+	github.com/dgrijalva/jwt-go v3.2.0+incompatible
+	github.com/labstack/gommon v0.0.0-20180312174116-6fe1405d73ec
+	github.com/mattn/go-colorable v0.0.9 // indirect
+	github.com/mattn/go-isatty v0.0.3 // indirect
+	github.com/pmezard/go-difflib v1.0.0 // indirect
+	github.com/stretchr/testify v1.2.1
+	github.com/valyala/bytebufferpool v0.0.0-20160817181652-e746df99fe4a // indirect
+	github.com/valyala/fasttemplate v0.0.0-20170224212429-dcecefd839c4
+	golang.org/x/crypto v0.0.0-20180312195533-182114d58262
+	golang.org/x/sys v0.0.0-20180312081825-c28acc882ebc // indirect
+)

+ 22 - 0
vendor/github.com/labstack/echo/go.sum

@@ -0,0 +1,22 @@
+github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/labstack/gommon v0.0.0-20180312174116-6fe1405d73ec h1:aYKwS4iCpqxskMuvI8+Byq0CxnnWHO/xuLk2pZJ96tY=
+github.com/labstack/gommon v0.0.0-20180312174116-6fe1405d73ec/go.mod h1:/tj9csK2iPSBvn+3NLM9e52usepMtrd5ilFYA+wQNJ4=
+github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
+github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
+github.com/mattn/go-isatty v0.0.3 h1:ns/ykhmWi7G9O+8a448SecJU3nSMBXJfqQkl0upE1jI=
+github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+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/testify v1.2.1 h1:52QO5WkIUcHGIR7EnGagH88x1bUzqGXTC5/1bDTUQ7U=
+github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/valyala/bytebufferpool v0.0.0-20160817181652-e746df99fe4a h1:AOcehBWpFhYPYw0ioDTppQzgI8pAAahVCiMSKTp9rbo=
+github.com/valyala/bytebufferpool v0.0.0-20160817181652-e746df99fe4a/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
+github.com/valyala/fasttemplate v0.0.0-20170224212429-dcecefd839c4 h1:gKMu1Bf6QINDnvyZuTaACm9ofY+PRh+5vFz4oxBZeF8=
+github.com/valyala/fasttemplate v0.0.0-20170224212429-dcecefd839c4/go.mod h1:50wTf68f99/Zt14pr046Tgt3Lp2vLyFZKzbFXTOabXw=
+golang.org/x/crypto v0.0.0-20180312195533-182114d58262 h1:1NLVUmR8SQ7cNNA5Vo7ronpXbR+5A+9IwIC/bLE7D8Y=
+golang.org/x/crypto v0.0.0-20180312195533-182114d58262/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/sys v0.0.0-20180312081825-c28acc882ebc h1:eCzBKjjvhDDXMoH5l7eA+YK1PEtyJ2QLj3f4IArr+zg=
+golang.org/x/sys v0.0.0-20180312081825-c28acc882ebc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=

+ 120 - 0
vendor/github.com/labstack/echo/group.go

@@ -0,0 +1,120 @@
+package echo
+
+import (
+	"path"
+)
+
+type (
+	// Group is a set of sub-routes for a specified route. It can be used for inner
+	// routes that share a common middleware or functionality that should be separate
+	// from the parent echo instance while still inheriting from it.
+	Group struct {
+		prefix     string
+		middleware []MiddlewareFunc
+		echo       *Echo
+	}
+)
+
+// Use implements `Echo#Use()` for sub-routes within the Group.
+func (g *Group) Use(middleware ...MiddlewareFunc) {
+	g.middleware = append(g.middleware, middleware...)
+	// Allow all requests to reach the group as they might get dropped if router
+	// doesn't find a match, making none of the group middleware process.
+	for _, p := range []string{"", "/*"} {
+		g.echo.Any(path.Clean(g.prefix+p), func(c Context) error {
+			return NotFoundHandler(c)
+		}, g.middleware...)
+	}
+}
+
+// CONNECT implements `Echo#CONNECT()` for sub-routes within the Group.
+func (g *Group) CONNECT(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+	return g.Add(CONNECT, path, h, m...)
+}
+
+// DELETE implements `Echo#DELETE()` for sub-routes within the Group.
+func (g *Group) DELETE(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+	return g.Add(DELETE, path, h, m...)
+}
+
+// GET implements `Echo#GET()` for sub-routes within the Group.
+func (g *Group) GET(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+	return g.Add(GET, path, h, m...)
+}
+
+// HEAD implements `Echo#HEAD()` for sub-routes within the Group.
+func (g *Group) HEAD(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+	return g.Add(HEAD, path, h, m...)
+}
+
+// OPTIONS implements `Echo#OPTIONS()` for sub-routes within the Group.
+func (g *Group) OPTIONS(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+	return g.Add(OPTIONS, path, h, m...)
+}
+
+// PATCH implements `Echo#PATCH()` for sub-routes within the Group.
+func (g *Group) PATCH(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+	return g.Add(PATCH, path, h, m...)
+}
+
+// POST implements `Echo#POST()` for sub-routes within the Group.
+func (g *Group) POST(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+	return g.Add(POST, path, h, m...)
+}
+
+// PUT implements `Echo#PUT()` for sub-routes within the Group.
+func (g *Group) PUT(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+	return g.Add(PUT, path, h, m...)
+}
+
+// TRACE implements `Echo#TRACE()` for sub-routes within the Group.
+func (g *Group) TRACE(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+	return g.Add(TRACE, path, h, m...)
+}
+
+// Any implements `Echo#Any()` for sub-routes within the Group.
+func (g *Group) Any(path string, handler HandlerFunc, middleware ...MiddlewareFunc) []*Route {
+	routes := make([]*Route, len(methods))
+	for i, m := range methods {
+		routes[i] = g.Add(m, path, handler, middleware...)
+	}
+	return routes
+}
+
+// Match implements `Echo#Match()` for sub-routes within the Group.
+func (g *Group) Match(methods []string, path string, handler HandlerFunc, middleware ...MiddlewareFunc) []*Route {
+	routes := make([]*Route, len(methods))
+	for i, m := range methods {
+		routes[i] = g.Add(m, path, handler, middleware...)
+	}
+	return routes
+}
+
+// Group creates a new sub-group with prefix and optional sub-group-level middleware.
+func (g *Group) Group(prefix string, middleware ...MiddlewareFunc) *Group {
+	m := make([]MiddlewareFunc, 0, len(g.middleware)+len(middleware))
+	m = append(m, g.middleware...)
+	m = append(m, middleware...)
+	return g.echo.Group(g.prefix+prefix, m...)
+}
+
+// Static implements `Echo#Static()` for sub-routes within the Group.
+func (g *Group) Static(prefix, root string) {
+	static(g, prefix, root)
+}
+
+// File implements `Echo#File()` for sub-routes within the Group.
+func (g *Group) File(path, file string) {
+	g.echo.File(g.prefix+path, file)
+}
+
+// Add implements `Echo#Add()` for sub-routes within the Group.
+func (g *Group) Add(method, path string, handler HandlerFunc, middleware ...MiddlewareFunc) *Route {
+	// Combine into a new slice to avoid accidentally passing the same slice for
+	// multiple routes, which would lead to later add() calls overwriting the
+	// middleware from earlier calls.
+	m := make([]MiddlewareFunc, 0, len(g.middleware)+len(middleware))
+	m = append(m, g.middleware...)
+	m = append(m, middleware...)
+	return g.echo.Add(method, g.prefix+path, handler, m...)
+}

+ 40 - 0
vendor/github.com/labstack/echo/log.go

@@ -0,0 +1,40 @@
+package echo
+
+import (
+	"io"
+
+	"github.com/labstack/gommon/log"
+)
+
+type (
+	// Logger defines the logging interface.
+	Logger interface {
+		Output() io.Writer
+		SetOutput(w io.Writer)
+		Prefix() string
+		SetPrefix(p string)
+		Level() log.Lvl
+		SetLevel(v log.Lvl)
+		Print(i ...interface{})
+		Printf(format string, args ...interface{})
+		Printj(j log.JSON)
+		Debug(i ...interface{})
+		Debugf(format string, args ...interface{})
+		Debugj(j log.JSON)
+		Info(i ...interface{})
+		Infof(format string, args ...interface{})
+		Infoj(j log.JSON)
+		Warn(i ...interface{})
+		Warnf(format string, args ...interface{})
+		Warnj(j log.JSON)
+		Error(i ...interface{})
+		Errorf(format string, args ...interface{})
+		Errorj(j log.JSON)
+		Fatal(i ...interface{})
+		Fatalj(j log.JSON)
+		Fatalf(format string, args ...interface{})
+		Panic(i ...interface{})
+		Panicj(j log.JSON)
+		Panicf(format string, args ...interface{})
+	}
+)

+ 106 - 0
vendor/github.com/labstack/echo/middleware/basic_auth.go

@@ -0,0 +1,106 @@
+package middleware
+
+import (
+	"encoding/base64"
+	"strconv"
+	"strings"
+
+	"github.com/labstack/echo"
+)
+
+type (
+	// BasicAuthConfig defines the config for BasicAuth middleware.
+	BasicAuthConfig struct {
+		// Skipper defines a function to skip middleware.
+		Skipper Skipper
+
+		// Validator is a function to validate BasicAuth credentials.
+		// Required.
+		Validator BasicAuthValidator
+
+		// Realm is a string to define realm attribute of BasicAuth.
+		// Default value "Restricted".
+		Realm string
+	}
+
+	// BasicAuthValidator defines a function to validate BasicAuth credentials.
+	BasicAuthValidator func(string, string, echo.Context) (bool, error)
+)
+
+const (
+	basic        = "basic"
+	defaultRealm = "Restricted"
+)
+
+var (
+	// DefaultBasicAuthConfig is the default BasicAuth middleware config.
+	DefaultBasicAuthConfig = BasicAuthConfig{
+		Skipper: DefaultSkipper,
+		Realm:   defaultRealm,
+	}
+)
+
+// BasicAuth returns an BasicAuth middleware.
+//
+// For valid credentials it calls the next handler.
+// For missing or invalid credentials, it sends "401 - Unauthorized" response.
+func BasicAuth(fn BasicAuthValidator) echo.MiddlewareFunc {
+	c := DefaultBasicAuthConfig
+	c.Validator = fn
+	return BasicAuthWithConfig(c)
+}
+
+// BasicAuthWithConfig returns an BasicAuth middleware with config.
+// See `BasicAuth()`.
+func BasicAuthWithConfig(config BasicAuthConfig) echo.MiddlewareFunc {
+	// Defaults
+	if config.Validator == nil {
+		panic("echo: basic-auth middleware requires a validator function")
+	}
+	if config.Skipper == nil {
+		config.Skipper = DefaultBasicAuthConfig.Skipper
+	}
+	if config.Realm == "" {
+		config.Realm = defaultRealm
+	}
+
+	return func(next echo.HandlerFunc) echo.HandlerFunc {
+		return func(c echo.Context) error {
+			if config.Skipper(c) {
+				return next(c)
+			}
+
+			auth := c.Request().Header.Get(echo.HeaderAuthorization)
+			l := len(basic)
+
+			if len(auth) > l+1 && strings.ToLower(auth[:l]) == basic {
+				b, err := base64.StdEncoding.DecodeString(auth[l+1:])
+				if err != nil {
+					return err
+				}
+				cred := string(b)
+				for i := 0; i < len(cred); i++ {
+					if cred[i] == ':' {
+						// Verify credentials
+						valid, err := config.Validator(cred[:i], cred[i+1:], c)
+						if err != nil {
+							return err
+						} else if valid {
+							return next(c)
+						}
+						break
+					}
+				}
+			}
+
+			realm := defaultRealm
+			if config.Realm != defaultRealm {
+				realm = strconv.Quote(config.Realm)
+			}
+
+			// Need to return `401` for browsers to pop-up login box.
+			c.Response().Header().Set(echo.HeaderWWWAuthenticate, basic+" realm="+realm)
+			return echo.ErrUnauthorized
+		}
+	}
+}

+ 111 - 0
vendor/github.com/labstack/echo/middleware/body_dump.go

@@ -0,0 +1,111 @@
+package middleware
+
+import (
+	"bufio"
+	"bytes"
+	"io"
+	"io/ioutil"
+	"net"
+	"net/http"
+
+	"github.com/labstack/echo"
+)
+
+type (
+	// BodyDumpConfig defines the config for BodyDump middleware.
+	BodyDumpConfig struct {
+		// Skipper defines a function to skip middleware.
+		Skipper Skipper
+
+		// Handler receives request and response payload.
+		// Required.
+		Handler BodyDumpHandler
+	}
+
+	// BodyDumpHandler receives the request and response payload.
+	BodyDumpHandler func(echo.Context, []byte, []byte)
+
+	bodyDumpResponseWriter struct {
+		io.Writer
+		http.ResponseWriter
+	}
+)
+
+var (
+	// DefaultBodyDumpConfig is the default BodyDump middleware config.
+	DefaultBodyDumpConfig = BodyDumpConfig{
+		Skipper: DefaultSkipper,
+	}
+)
+
+// BodyDump returns a BodyDump middleware.
+//
+// BodyLimit middleware captures the request and response payload and calls the
+// registered handler.
+func BodyDump(handler BodyDumpHandler) echo.MiddlewareFunc {
+	c := DefaultBodyDumpConfig
+	c.Handler = handler
+	return BodyDumpWithConfig(c)
+}
+
+// BodyDumpWithConfig returns a BodyDump middleware with config.
+// See: `BodyDump()`.
+func BodyDumpWithConfig(config BodyDumpConfig) echo.MiddlewareFunc {
+	// Defaults
+	if config.Handler == nil {
+		panic("echo: body-dump middleware requires a handler function")
+	}
+	if config.Skipper == nil {
+		config.Skipper = DefaultBodyDumpConfig.Skipper
+	}
+
+	return func(next echo.HandlerFunc) echo.HandlerFunc {
+		return func(c echo.Context) (err error) {
+			if config.Skipper(c) {
+				return next(c)
+			}
+
+			// Request
+			reqBody := []byte{}
+			if c.Request().Body != nil { // Read
+				reqBody, _ = ioutil.ReadAll(c.Request().Body)
+			}
+			c.Request().Body = ioutil.NopCloser(bytes.NewBuffer(reqBody)) // Reset
+
+			// Response
+			resBody := new(bytes.Buffer)
+			mw := io.MultiWriter(c.Response().Writer, resBody)
+			writer := &bodyDumpResponseWriter{Writer: mw, ResponseWriter: c.Response().Writer}
+			c.Response().Writer = writer
+
+			if err = next(c); err != nil {
+				c.Error(err)
+			}
+
+			// Callback
+			config.Handler(c, reqBody, resBody.Bytes())
+
+			return
+		}
+	}
+}
+
+func (w *bodyDumpResponseWriter) WriteHeader(code int) {
+	w.ResponseWriter.WriteHeader(code)
+}
+
+func (w *bodyDumpResponseWriter) Write(b []byte) (int, error) {
+	return w.Writer.Write(b)
+}
+
+func (w *bodyDumpResponseWriter) Flush() {
+	w.ResponseWriter.(http.Flusher).Flush()
+}
+
+func (w *bodyDumpResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+	return w.ResponseWriter.(http.Hijacker).Hijack()
+}
+
+func (w *bodyDumpResponseWriter) CloseNotify() <-chan bool {
+	return w.ResponseWriter.(http.CloseNotifier).CloseNotify()
+}

+ 117 - 0
vendor/github.com/labstack/echo/middleware/body_limit.go

@@ -0,0 +1,117 @@
+package middleware
+
+import (
+	"fmt"
+	"io"
+	"sync"
+
+	"github.com/labstack/echo"
+	"github.com/labstack/gommon/bytes"
+)
+
+type (
+	// BodyLimitConfig defines the config for BodyLimit middleware.
+	BodyLimitConfig struct {
+		// Skipper defines a function to skip middleware.
+		Skipper Skipper
+
+		// Maximum allowed size for a request body, it can be specified
+		// as `4x` or `4xB`, where x is one of the multiple from K, M, G, T or P.
+		Limit string `yaml:"limit"`
+		limit int64
+	}
+
+	limitedReader struct {
+		BodyLimitConfig
+		reader  io.ReadCloser
+		read    int64
+		context echo.Context
+	}
+)
+
+var (
+	// DefaultBodyLimitConfig is the default BodyLimit middleware config.
+	DefaultBodyLimitConfig = BodyLimitConfig{
+		Skipper: DefaultSkipper,
+	}
+)
+
+// BodyLimit returns a BodyLimit middleware.
+//
+// BodyLimit middleware sets the maximum allowed size for a request body, if the
+// size exceeds the configured limit, it sends "413 - Request Entity Too Large"
+// response. The BodyLimit is determined based on both `Content-Length` request
+// header and actual content read, which makes it super secure.
+// Limit can be specified as `4x` or `4xB`, where x is one of the multiple from K, M,
+// G, T or P.
+func BodyLimit(limit string) echo.MiddlewareFunc {
+	c := DefaultBodyLimitConfig
+	c.Limit = limit
+	return BodyLimitWithConfig(c)
+}
+
+// BodyLimitWithConfig returns a BodyLimit middleware with config.
+// See: `BodyLimit()`.
+func BodyLimitWithConfig(config BodyLimitConfig) echo.MiddlewareFunc {
+	// Defaults
+	if config.Skipper == nil {
+		config.Skipper = DefaultBodyLimitConfig.Skipper
+	}
+
+	limit, err := bytes.Parse(config.Limit)
+	if err != nil {
+		panic(fmt.Errorf("echo: invalid body-limit=%s", config.Limit))
+	}
+	config.limit = limit
+	pool := limitedReaderPool(config)
+
+	return func(next echo.HandlerFunc) echo.HandlerFunc {
+		return func(c echo.Context) error {
+			if config.Skipper(c) {
+				return next(c)
+			}
+
+			req := c.Request()
+
+			// Based on content length
+			if req.ContentLength > config.limit {
+				return echo.ErrStatusRequestEntityTooLarge
+			}
+
+			// Based on content read
+			r := pool.Get().(*limitedReader)
+			r.Reset(req.Body, c)
+			defer pool.Put(r)
+			req.Body = r
+
+			return next(c)
+		}
+	}
+}
+
+func (r *limitedReader) Read(b []byte) (n int, err error) {
+	n, err = r.reader.Read(b)
+	r.read += int64(n)
+	if r.read > r.limit {
+		return n, echo.ErrStatusRequestEntityTooLarge
+	}
+	return
+}
+
+func (r *limitedReader) Close() error {
+	return r.reader.Close()
+}
+
+func (r *limitedReader) Reset(reader io.ReadCloser, context echo.Context) {
+	r.reader = reader
+	r.context = context
+	r.read = 0
+}
+
+func limitedReaderPool(c BodyLimitConfig) sync.Pool {
+	return sync.Pool{
+		New: func() interface{} {
+			return &limitedReader{BodyLimitConfig: c}
+		},
+	}
+}

+ 122 - 0
vendor/github.com/labstack/echo/middleware/compress.go

@@ -0,0 +1,122 @@
+package middleware
+
+import (
+	"bufio"
+	"compress/gzip"
+	"io"
+	"io/ioutil"
+	"net"
+	"net/http"
+	"strings"
+
+	"github.com/labstack/echo"
+)
+
+type (
+	// GzipConfig defines the config for Gzip middleware.
+	GzipConfig struct {
+		// Skipper defines a function to skip middleware.
+		Skipper Skipper
+
+		// Gzip compression level.
+		// Optional. Default value -1.
+		Level int `yaml:"level"`
+	}
+
+	gzipResponseWriter struct {
+		io.Writer
+		http.ResponseWriter
+	}
+)
+
+const (
+	gzipScheme = "gzip"
+)
+
+var (
+	// DefaultGzipConfig is the default Gzip middleware config.
+	DefaultGzipConfig = GzipConfig{
+		Skipper: DefaultSkipper,
+		Level:   -1,
+	}
+)
+
+// Gzip returns a middleware which compresses HTTP response using gzip compression
+// scheme.
+func Gzip() echo.MiddlewareFunc {
+	return GzipWithConfig(DefaultGzipConfig)
+}
+
+// GzipWithConfig return Gzip middleware with config.
+// See: `Gzip()`.
+func GzipWithConfig(config GzipConfig) echo.MiddlewareFunc {
+	// Defaults
+	if config.Skipper == nil {
+		config.Skipper = DefaultGzipConfig.Skipper
+	}
+	if config.Level == 0 {
+		config.Level = DefaultGzipConfig.Level
+	}
+
+	return func(next echo.HandlerFunc) echo.HandlerFunc {
+		return func(c echo.Context) error {
+			if config.Skipper(c) {
+				return next(c)
+			}
+
+			res := c.Response()
+			res.Header().Add(echo.HeaderVary, echo.HeaderAcceptEncoding)
+			if strings.Contains(c.Request().Header.Get(echo.HeaderAcceptEncoding), gzipScheme) {
+				res.Header().Set(echo.HeaderContentEncoding, gzipScheme) // Issue #806
+				rw := res.Writer
+				w, err := gzip.NewWriterLevel(rw, config.Level)
+				if err != nil {
+					return err
+				}
+				defer func() {
+					if res.Size == 0 {
+						if res.Header().Get(echo.HeaderContentEncoding) == gzipScheme {
+							res.Header().Del(echo.HeaderContentEncoding)
+						}
+						// We have to reset response to it's pristine state when
+						// nothing is written to body or error is returned.
+						// See issue #424, #407.
+						res.Writer = rw
+						w.Reset(ioutil.Discard)
+					}
+					w.Close()
+				}()
+				grw := &gzipResponseWriter{Writer: w, ResponseWriter: rw}
+				res.Writer = grw
+			}
+			return next(c)
+		}
+	}
+}
+
+func (w *gzipResponseWriter) WriteHeader(code int) {
+	if code == http.StatusNoContent { // Issue #489
+		w.ResponseWriter.Header().Del(echo.HeaderContentEncoding)
+	}
+	w.Header().Del(echo.HeaderContentLength) // Issue #444
+	w.ResponseWriter.WriteHeader(code)
+}
+
+func (w *gzipResponseWriter) Write(b []byte) (int, error) {
+	if w.Header().Get(echo.HeaderContentType) == "" {
+		w.Header().Set(echo.HeaderContentType, http.DetectContentType(b))
+	}
+	return w.Writer.Write(b)
+}
+
+func (w *gzipResponseWriter) Flush() {
+	w.Writer.(*gzip.Writer).Flush()
+}
+
+func (w *gzipResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+	return w.ResponseWriter.(http.Hijacker).Hijack()
+}
+
+func (w *gzipResponseWriter) CloseNotify() <-chan bool {
+	return w.ResponseWriter.(http.CloseNotifier).CloseNotify()
+}

+ 143 - 0
vendor/github.com/labstack/echo/middleware/cors.go

@@ -0,0 +1,143 @@
+package middleware
+
+import (
+	"net/http"
+	"strconv"
+	"strings"
+
+	"github.com/labstack/echo"
+)
+
+type (
+	// CORSConfig defines the config for CORS middleware.
+	CORSConfig struct {
+		// Skipper defines a function to skip middleware.
+		Skipper Skipper
+
+		// AllowOrigin defines a list of origins that may access the resource.
+		// Optional. Default value []string{"*"}.
+		AllowOrigins []string `yaml:"allow_origins"`
+
+		// AllowMethods defines a list methods allowed when accessing the resource.
+		// This is used in response to a preflight request.
+		// Optional. Default value DefaultCORSConfig.AllowMethods.
+		AllowMethods []string `yaml:"allow_methods"`
+
+		// AllowHeaders defines a list of request headers that can be used when
+		// making the actual request. This in response to a preflight request.
+		// Optional. Default value []string{}.
+		AllowHeaders []string `yaml:"allow_headers"`
+
+		// AllowCredentials indicates whether or not the response to the request
+		// can be exposed when the credentials flag is true. When used as part of
+		// a response to a preflight request, this indicates whether or not the
+		// actual request can be made using credentials.
+		// Optional. Default value false.
+		AllowCredentials bool `yaml:"allow_credentials"`
+
+		// ExposeHeaders defines a whitelist headers that clients are allowed to
+		// access.
+		// Optional. Default value []string{}.
+		ExposeHeaders []string `yaml:"expose_headers"`
+
+		// MaxAge indicates how long (in seconds) the results of a preflight request
+		// can be cached.
+		// Optional. Default value 0.
+		MaxAge int `yaml:"max_age"`
+	}
+)
+
+var (
+	// DefaultCORSConfig is the default CORS middleware config.
+	DefaultCORSConfig = CORSConfig{
+		Skipper:      DefaultSkipper,
+		AllowOrigins: []string{"*"},
+		AllowMethods: []string{echo.GET, echo.HEAD, echo.PUT, echo.PATCH, echo.POST, echo.DELETE},
+	}
+)
+
+// CORS returns a Cross-Origin Resource Sharing (CORS) middleware.
+// See: https://developer.mozilla.org/en/docs/Web/HTTP/Access_control_CORS
+func CORS() echo.MiddlewareFunc {
+	return CORSWithConfig(DefaultCORSConfig)
+}
+
+// CORSWithConfig returns a CORS middleware with config.
+// See: `CORS()`.
+func CORSWithConfig(config CORSConfig) echo.MiddlewareFunc {
+	// Defaults
+	if config.Skipper == nil {
+		config.Skipper = DefaultCORSConfig.Skipper
+	}
+	if len(config.AllowOrigins) == 0 {
+		config.AllowOrigins = DefaultCORSConfig.AllowOrigins
+	}
+	if len(config.AllowMethods) == 0 {
+		config.AllowMethods = DefaultCORSConfig.AllowMethods
+	}
+
+	allowMethods := strings.Join(config.AllowMethods, ",")
+	allowHeaders := strings.Join(config.AllowHeaders, ",")
+	exposeHeaders := strings.Join(config.ExposeHeaders, ",")
+	maxAge := strconv.Itoa(config.MaxAge)
+
+	return func(next echo.HandlerFunc) echo.HandlerFunc {
+		return func(c echo.Context) error {
+			if config.Skipper(c) {
+				return next(c)
+			}
+
+			req := c.Request()
+			res := c.Response()
+			origin := req.Header.Get(echo.HeaderOrigin)
+			allowOrigin := ""
+
+			// Check allowed origins
+			for _, o := range config.AllowOrigins {
+				if o == "*" && config.AllowCredentials {
+					allowOrigin = origin
+					break
+				}
+				if o == "*" || o == origin {
+					allowOrigin = o
+					break
+				}
+			}
+
+			// Simple request
+			if req.Method != echo.OPTIONS {
+				res.Header().Add(echo.HeaderVary, echo.HeaderOrigin)
+				res.Header().Set(echo.HeaderAccessControlAllowOrigin, allowOrigin)
+				if config.AllowCredentials {
+					res.Header().Set(echo.HeaderAccessControlAllowCredentials, "true")
+				}
+				if exposeHeaders != "" {
+					res.Header().Set(echo.HeaderAccessControlExposeHeaders, exposeHeaders)
+				}
+				return next(c)
+			}
+
+			// Preflight request
+			res.Header().Add(echo.HeaderVary, echo.HeaderOrigin)
+			res.Header().Add(echo.HeaderVary, echo.HeaderAccessControlRequestMethod)
+			res.Header().Add(echo.HeaderVary, echo.HeaderAccessControlRequestHeaders)
+			res.Header().Set(echo.HeaderAccessControlAllowOrigin, allowOrigin)
+			res.Header().Set(echo.HeaderAccessControlAllowMethods, allowMethods)
+			if config.AllowCredentials {
+				res.Header().Set(echo.HeaderAccessControlAllowCredentials, "true")
+			}
+			if allowHeaders != "" {
+				res.Header().Set(echo.HeaderAccessControlAllowHeaders, allowHeaders)
+			} else {
+				h := req.Header.Get(echo.HeaderAccessControlRequestHeaders)
+				if h != "" {
+					res.Header().Set(echo.HeaderAccessControlAllowHeaders, h)
+				}
+			}
+			if config.MaxAge > 0 {
+				res.Header().Set(echo.HeaderAccessControlMaxAge, maxAge)
+			}
+			return c.NoContent(http.StatusNoContent)
+		}
+	}
+}

+ 210 - 0
vendor/github.com/labstack/echo/middleware/csrf.go

@@ -0,0 +1,210 @@
+package middleware
+
+import (
+	"crypto/subtle"
+	"errors"
+	"net/http"
+	"strings"
+	"time"
+
+	"github.com/labstack/echo"
+	"github.com/labstack/gommon/random"
+)
+
+type (
+	// CSRFConfig defines the config for CSRF middleware.
+	CSRFConfig struct {
+		// Skipper defines a function to skip middleware.
+		Skipper Skipper
+
+		// TokenLength is the length of the generated token.
+		TokenLength uint8 `yaml:"token_length"`
+		// Optional. Default value 32.
+
+		// TokenLookup is a string in the form of "<source>:<key>" that is used
+		// to extract token from the request.
+		// Optional. Default value "header:X-CSRF-Token".
+		// Possible values:
+		// - "header:<name>"
+		// - "form:<name>"
+		// - "query:<name>"
+		TokenLookup string `yaml:"token_lookup"`
+
+		// Context key to store generated CSRF token into context.
+		// Optional. Default value "csrf".
+		ContextKey string `yaml:"context_key"`
+
+		// Name of the CSRF cookie. This cookie will store CSRF token.
+		// Optional. Default value "csrf".
+		CookieName string `yaml:"cookie_name"`
+
+		// Domain of the CSRF cookie.
+		// Optional. Default value none.
+		CookieDomain string `yaml:"cookie_domain"`
+
+		// Path of the CSRF cookie.
+		// Optional. Default value none.
+		CookiePath string `yaml:"cookie_path"`
+
+		// Max age (in seconds) of the CSRF cookie.
+		// Optional. Default value 86400 (24hr).
+		CookieMaxAge int `yaml:"cookie_max_age"`
+
+		// Indicates if CSRF cookie is secure.
+		// Optional. Default value false.
+		CookieSecure bool `yaml:"cookie_secure"`
+
+		// Indicates if CSRF cookie is HTTP only.
+		// Optional. Default value false.
+		CookieHTTPOnly bool `yaml:"cookie_http_only"`
+	}
+
+	// csrfTokenExtractor defines a function that takes `echo.Context` and returns
+	// either a token or an error.
+	csrfTokenExtractor func(echo.Context) (string, error)
+)
+
+var (
+	// DefaultCSRFConfig is the default CSRF middleware config.
+	DefaultCSRFConfig = CSRFConfig{
+		Skipper:      DefaultSkipper,
+		TokenLength:  32,
+		TokenLookup:  "header:" + echo.HeaderXCSRFToken,
+		ContextKey:   "csrf",
+		CookieName:   "_csrf",
+		CookieMaxAge: 86400,
+	}
+)
+
+// CSRF returns a Cross-Site Request Forgery (CSRF) middleware.
+// See: https://en.wikipedia.org/wiki/Cross-site_request_forgery
+func CSRF() echo.MiddlewareFunc {
+	c := DefaultCSRFConfig
+	return CSRFWithConfig(c)
+}
+
+// CSRFWithConfig returns a CSRF middleware with config.
+// See `CSRF()`.
+func CSRFWithConfig(config CSRFConfig) echo.MiddlewareFunc {
+	// Defaults
+	if config.Skipper == nil {
+		config.Skipper = DefaultCSRFConfig.Skipper
+	}
+	if config.TokenLength == 0 {
+		config.TokenLength = DefaultCSRFConfig.TokenLength
+	}
+	if config.TokenLookup == "" {
+		config.TokenLookup = DefaultCSRFConfig.TokenLookup
+	}
+	if config.ContextKey == "" {
+		config.ContextKey = DefaultCSRFConfig.ContextKey
+	}
+	if config.CookieName == "" {
+		config.CookieName = DefaultCSRFConfig.CookieName
+	}
+	if config.CookieMaxAge == 0 {
+		config.CookieMaxAge = DefaultCSRFConfig.CookieMaxAge
+	}
+
+	// Initialize
+	parts := strings.Split(config.TokenLookup, ":")
+	extractor := csrfTokenFromHeader(parts[1])
+	switch parts[0] {
+	case "form":
+		extractor = csrfTokenFromForm(parts[1])
+	case "query":
+		extractor = csrfTokenFromQuery(parts[1])
+	}
+
+	return func(next echo.HandlerFunc) echo.HandlerFunc {
+		return func(c echo.Context) error {
+			if config.Skipper(c) {
+				return next(c)
+			}
+
+			req := c.Request()
+			k, err := c.Cookie(config.CookieName)
+			token := ""
+
+			// Generate token
+			if err != nil {
+				token = random.String(config.TokenLength)
+			} else {
+				// Reuse token
+				token = k.Value
+			}
+
+			switch req.Method {
+			case echo.GET, echo.HEAD, echo.OPTIONS, echo.TRACE:
+			default:
+				// Validate token only for requests which are not defined as 'safe' by RFC7231
+				clientToken, err := extractor(c)
+				if err != nil {
+					return echo.NewHTTPError(http.StatusBadRequest, err.Error())
+				}
+				if !validateCSRFToken(token, clientToken) {
+					return echo.NewHTTPError(http.StatusForbidden, "invalid csrf token")
+				}
+			}
+
+			// Set CSRF cookie
+			cookie := new(http.Cookie)
+			cookie.Name = config.CookieName
+			cookie.Value = token
+			if config.CookiePath != "" {
+				cookie.Path = config.CookiePath
+			}
+			if config.CookieDomain != "" {
+				cookie.Domain = config.CookieDomain
+			}
+			cookie.Expires = time.Now().Add(time.Duration(config.CookieMaxAge) * time.Second)
+			cookie.Secure = config.CookieSecure
+			cookie.HttpOnly = config.CookieHTTPOnly
+			c.SetCookie(cookie)
+
+			// Store token in the context
+			c.Set(config.ContextKey, token)
+
+			// Protect clients from caching the response
+			c.Response().Header().Add(echo.HeaderVary, echo.HeaderCookie)
+
+			return next(c)
+		}
+	}
+}
+
+// csrfTokenFromForm returns a `csrfTokenExtractor` that extracts token from the
+// provided request header.
+func csrfTokenFromHeader(header string) csrfTokenExtractor {
+	return func(c echo.Context) (string, error) {
+		return c.Request().Header.Get(header), nil
+	}
+}
+
+// csrfTokenFromForm returns a `csrfTokenExtractor` that extracts token from the
+// provided form parameter.
+func csrfTokenFromForm(param string) csrfTokenExtractor {
+	return func(c echo.Context) (string, error) {
+		token := c.FormValue(param)
+		if token == "" {
+			return "", errors.New("missing csrf token in the form parameter")
+		}
+		return token, nil
+	}
+}
+
+// csrfTokenFromQuery returns a `csrfTokenExtractor` that extracts token from the
+// provided query parameter.
+func csrfTokenFromQuery(param string) csrfTokenExtractor {
+	return func(c echo.Context) (string, error) {
+		token := c.QueryParam(param)
+		if token == "" {
+			return "", errors.New("missing csrf token in the query string")
+		}
+		return token, nil
+	}
+}
+
+func validateCSRFToken(token, clientToken string) bool {
+	return subtle.ConstantTimeCompare([]byte(token), []byte(clientToken)) == 1
+}

+ 227 - 0
vendor/github.com/labstack/echo/middleware/jwt.go

@@ -0,0 +1,227 @@
+package middleware
+
+import (
+	"fmt"
+	"net/http"
+	"reflect"
+	"strings"
+
+	"github.com/dgrijalva/jwt-go"
+	"github.com/labstack/echo"
+)
+
+type (
+	// JWTConfig defines the config for JWT middleware.
+	JWTConfig struct {
+		// Skipper defines a function to skip middleware.
+		Skipper Skipper
+
+		// BeforeFunc defines a function which is executed just before the middleware.
+		BeforeFunc BeforeFunc
+
+		// SuccessHandler defines a function which is executed for a valid token.
+		SuccessHandler JWTSuccessHandler
+
+		// ErrorHandler defines a function which is executed for an invalid token.
+		// It may be used to define a custom JWT error.
+		ErrorHandler JWTErrorHandler
+
+		// Signing key to validate token.
+		// Required.
+		SigningKey interface{}
+
+		// Signing method, used to check token signing method.
+		// Optional. Default value HS256.
+		SigningMethod string
+
+		// Context key to store user information from the token into context.
+		// Optional. Default value "user".
+		ContextKey string
+
+		// Claims are extendable claims data defining token content.
+		// Optional. Default value jwt.MapClaims
+		Claims jwt.Claims
+
+		// TokenLookup is a string in the form of "<source>:<name>" that is used
+		// to extract token from the request.
+		// Optional. Default value "header:Authorization".
+		// Possible values:
+		// - "header:<name>"
+		// - "query:<name>"
+		// - "cookie:<name>"
+		TokenLookup string
+
+		// AuthScheme to be used in the Authorization header.
+		// Optional. Default value "Bearer".
+		AuthScheme string
+
+		keyFunc jwt.Keyfunc
+	}
+
+	// JWTSuccessHandler defines a function which is executed for a valid token.
+	JWTSuccessHandler func(echo.Context)
+
+	// JWTErrorHandler defines a function which is executed for an invalid token.
+	JWTErrorHandler func(error) error
+
+	jwtExtractor func(echo.Context) (string, error)
+)
+
+// Algorithms
+const (
+	AlgorithmHS256 = "HS256"
+)
+
+// Errors
+var (
+	ErrJWTMissing = echo.NewHTTPError(http.StatusBadRequest, "missing or malformed jwt")
+)
+
+var (
+	// DefaultJWTConfig is the default JWT auth middleware config.
+	DefaultJWTConfig = JWTConfig{
+		Skipper:       DefaultSkipper,
+		SigningMethod: AlgorithmHS256,
+		ContextKey:    "user",
+		TokenLookup:   "header:" + echo.HeaderAuthorization,
+		AuthScheme:    "Bearer",
+		Claims:        jwt.MapClaims{},
+	}
+)
+
+// JWT returns a JSON Web Token (JWT) auth middleware.
+//
+// For valid token, it sets the user in context and calls next handler.
+// For invalid token, it returns "401 - Unauthorized" error.
+// For missing token, it returns "400 - Bad Request" error.
+//
+// See: https://jwt.io/introduction
+// See `JWTConfig.TokenLookup`
+func JWT(key interface{}) echo.MiddlewareFunc {
+	c := DefaultJWTConfig
+	c.SigningKey = key
+	return JWTWithConfig(c)
+}
+
+// JWTWithConfig returns a JWT auth middleware with config.
+// See: `JWT()`.
+func JWTWithConfig(config JWTConfig) echo.MiddlewareFunc {
+	// Defaults
+	if config.Skipper == nil {
+		config.Skipper = DefaultJWTConfig.Skipper
+	}
+	if config.SigningKey == nil {
+		panic("echo: jwt middleware requires signing key")
+	}
+	if config.SigningMethod == "" {
+		config.SigningMethod = DefaultJWTConfig.SigningMethod
+	}
+	if config.ContextKey == "" {
+		config.ContextKey = DefaultJWTConfig.ContextKey
+	}
+	if config.Claims == nil {
+		config.Claims = DefaultJWTConfig.Claims
+	}
+	if config.TokenLookup == "" {
+		config.TokenLookup = DefaultJWTConfig.TokenLookup
+	}
+	if config.AuthScheme == "" {
+		config.AuthScheme = DefaultJWTConfig.AuthScheme
+	}
+	config.keyFunc = func(t *jwt.Token) (interface{}, error) {
+		// Check the signing method
+		if t.Method.Alg() != config.SigningMethod {
+			return nil, fmt.Errorf("unexpected jwt signing method=%v", t.Header["alg"])
+		}
+		return config.SigningKey, nil
+	}
+
+	// Initialize
+	parts := strings.Split(config.TokenLookup, ":")
+	extractor := jwtFromHeader(parts[1], config.AuthScheme)
+	switch parts[0] {
+	case "query":
+		extractor = jwtFromQuery(parts[1])
+	case "cookie":
+		extractor = jwtFromCookie(parts[1])
+	}
+
+	return func(next echo.HandlerFunc) echo.HandlerFunc {
+		return func(c echo.Context) error {
+			if config.Skipper(c) {
+				return next(c)
+			}
+
+			if config.BeforeFunc != nil {
+				config.BeforeFunc(c)
+			}
+
+			auth, err := extractor(c)
+			if err != nil {
+				if config.ErrorHandler != nil {
+					return config.ErrorHandler(err)
+				}
+				return err
+			}
+			token := new(jwt.Token)
+			// Issue #647, #656
+			if _, ok := config.Claims.(jwt.MapClaims); ok {
+				token, err = jwt.Parse(auth, config.keyFunc)
+			} else {
+				t := reflect.ValueOf(config.Claims).Type().Elem()
+				claims := reflect.New(t).Interface().(jwt.Claims)
+				token, err = jwt.ParseWithClaims(auth, claims, config.keyFunc)
+			}
+			if err == nil && token.Valid {
+				// Store user information from token into context.
+				c.Set(config.ContextKey, token)
+				if config.SuccessHandler != nil {
+					config.SuccessHandler(c)
+				}
+				return next(c)
+			}
+			if config.ErrorHandler != nil {
+				return config.ErrorHandler(err)
+			}
+			return &echo.HTTPError{
+				Code:     http.StatusUnauthorized,
+				Message:  "invalid or expired jwt",
+				Internal: err,
+			}
+		}
+	}
+}
+
+// jwtFromHeader returns a `jwtExtractor` that extracts token from the request header.
+func jwtFromHeader(header string, authScheme string) jwtExtractor {
+	return func(c echo.Context) (string, error) {
+		auth := c.Request().Header.Get(header)
+		l := len(authScheme)
+		if len(auth) > l+1 && auth[:l] == authScheme {
+			return auth[l+1:], nil
+		}
+		return "", ErrJWTMissing
+	}
+}
+
+// jwtFromQuery returns a `jwtExtractor` that extracts token from the query string.
+func jwtFromQuery(param string) jwtExtractor {
+	return func(c echo.Context) (string, error) {
+		token := c.QueryParam(param)
+		if token == "" {
+			return "", ErrJWTMissing
+		}
+		return token, nil
+	}
+}
+
+// jwtFromCookie returns a `jwtExtractor` that extracts token from the named cookie.
+func jwtFromCookie(name string) jwtExtractor {
+	return func(c echo.Context) (string, error) {
+		cookie, err := c.Cookie(name)
+		if err != nil {
+			return "", ErrJWTMissing
+		}
+		return cookie.Value, nil
+	}
+}

+ 150 - 0
vendor/github.com/labstack/echo/middleware/key_auth.go

@@ -0,0 +1,150 @@
+package middleware
+
+import (
+	"errors"
+	"net/http"
+	"strings"
+
+	"github.com/labstack/echo"
+)
+
+type (
+	// KeyAuthConfig defines the config for KeyAuth middleware.
+	KeyAuthConfig struct {
+		// Skipper defines a function to skip middleware.
+		Skipper Skipper
+
+		// KeyLookup is a string in the form of "<source>:<name>" that is used
+		// to extract key from the request.
+		// Optional. Default value "header:Authorization".
+		// Possible values:
+		// - "header:<name>"
+		// - "query:<name>"
+		// - "form:<name>"
+		KeyLookup string `yaml:"key_lookup"`
+
+		// AuthScheme to be used in the Authorization header.
+		// Optional. Default value "Bearer".
+		AuthScheme string
+
+		// Validator is a function to validate key.
+		// Required.
+		Validator KeyAuthValidator
+	}
+
+	// KeyAuthValidator defines a function to validate KeyAuth credentials.
+	KeyAuthValidator func(string, echo.Context) (bool, error)
+
+	keyExtractor func(echo.Context) (string, error)
+)
+
+var (
+	// DefaultKeyAuthConfig is the default KeyAuth middleware config.
+	DefaultKeyAuthConfig = KeyAuthConfig{
+		Skipper:    DefaultSkipper,
+		KeyLookup:  "header:" + echo.HeaderAuthorization,
+		AuthScheme: "Bearer",
+	}
+)
+
+// KeyAuth returns an KeyAuth middleware.
+//
+// For valid key it calls the next handler.
+// For invalid key, it sends "401 - Unauthorized" response.
+// For missing key, it sends "400 - Bad Request" response.
+func KeyAuth(fn KeyAuthValidator) echo.MiddlewareFunc {
+	c := DefaultKeyAuthConfig
+	c.Validator = fn
+	return KeyAuthWithConfig(c)
+}
+
+// KeyAuthWithConfig returns an KeyAuth middleware with config.
+// See `KeyAuth()`.
+func KeyAuthWithConfig(config KeyAuthConfig) echo.MiddlewareFunc {
+	// Defaults
+	if config.Skipper == nil {
+		config.Skipper = DefaultKeyAuthConfig.Skipper
+	}
+	// Defaults
+	if config.AuthScheme == "" {
+		config.AuthScheme = DefaultKeyAuthConfig.AuthScheme
+	}
+	if config.KeyLookup == "" {
+		config.KeyLookup = DefaultKeyAuthConfig.KeyLookup
+	}
+	if config.Validator == nil {
+		panic("echo: key-auth middleware requires a validator function")
+	}
+
+	// Initialize
+	parts := strings.Split(config.KeyLookup, ":")
+	extractor := keyFromHeader(parts[1], config.AuthScheme)
+	switch parts[0] {
+	case "query":
+		extractor = keyFromQuery(parts[1])
+	case "form":
+		extractor = keyFromForm(parts[1])
+	}
+
+	return func(next echo.HandlerFunc) echo.HandlerFunc {
+		return func(c echo.Context) error {
+			if config.Skipper(c) {
+				return next(c)
+			}
+
+			// Extract and verify key
+			key, err := extractor(c)
+			if err != nil {
+				return echo.NewHTTPError(http.StatusBadRequest, err.Error())
+			}
+			valid, err := config.Validator(key, c)
+			if err != nil {
+				return err
+			} else if valid {
+				return next(c)
+			}
+
+			return echo.ErrUnauthorized
+		}
+	}
+}
+
+// keyFromHeader returns a `keyExtractor` that extracts key from the request header.
+func keyFromHeader(header string, authScheme string) keyExtractor {
+	return func(c echo.Context) (string, error) {
+		auth := c.Request().Header.Get(header)
+		if auth == "" {
+			return "", errors.New("missing key in request header")
+		}
+		if header == echo.HeaderAuthorization {
+			l := len(authScheme)
+			if len(auth) > l+1 && auth[:l] == authScheme {
+				return auth[l+1:], nil
+			}
+			return "", errors.New("invalid key in the request header")
+		}
+		return auth, nil
+	}
+}
+
+// keyFromQuery returns a `keyExtractor` that extracts key from the query string.
+func keyFromQuery(param string) keyExtractor {
+	return func(c echo.Context) (string, error) {
+		key := c.QueryParam(param)
+		if key == "" {
+			return "", errors.New("missing key in the query string")
+		}
+		return key, nil
+	}
+}
+
+// keyFromForm returns a `keyExtractor` that extracts key from the form.
+func keyFromForm(param string) keyExtractor {
+	return func(c echo.Context) (string, error) {
+		key := c.FormValue(param)
+		if key == "" {
+			return "", errors.New("missing key in the form")
+		}
+		return key, nil
+	}
+}

+ 217 - 0
vendor/github.com/labstack/echo/middleware/logger.go

@@ -0,0 +1,217 @@
+package middleware
+
+import (
+	"bytes"
+	"io"
+	"os"
+	"strconv"
+	"strings"
+	"sync"
+	"time"
+
+	"github.com/labstack/echo"
+	"github.com/labstack/gommon/color"
+	"github.com/valyala/fasttemplate"
+)
+
+type (
+	// LoggerConfig defines the config for Logger middleware.
+	LoggerConfig struct {
+		// Skipper defines a function to skip middleware.
+		Skipper Skipper
+
+		// Tags to constructed the logger format.
+		//
+		// - time_unix
+		// - time_unix_nano
+		// - time_rfc3339
+		// - time_rfc3339_nano
+		// - time_custom
+		// - id (Request ID)
+		// - remote_ip
+		// - uri
+		// - host
+		// - method
+		// - path
+		// - protocol
+		// - referer
+		// - user_agent
+		// - status
+		// - error
+		// - latency (In nanoseconds)
+		// - latency_human (Human readable)
+		// - bytes_in (Bytes received)
+		// - bytes_out (Bytes sent)
+		// - header:<NAME>
+		// - query:<NAME>
+		// - form:<NAME>
+		//
+		// Example "${remote_ip} ${status}"
+		//
+		// Optional. Default value DefaultLoggerConfig.Format.
+		Format string `yaml:"format"`
+
+		// Optional. Default value DefaultLoggerConfig.CustomTimeFormat.
+		CustomTimeFormat string `yaml:"custom_time_format"`
+
+		// Output is a writer where logs in JSON format are written.
+		// Optional. Default value os.Stdout.
+		Output io.Writer
+
+		template *fasttemplate.Template
+		colorer  *color.Color
+		pool     *sync.Pool
+	}
+)
+
+var (
+	// DefaultLoggerConfig is the default Logger middleware config.
+	DefaultLoggerConfig = LoggerConfig{
+		Skipper: DefaultSkipper,
+		Format: `{"time":"${time_rfc3339_nano}","id":"${id}","remote_ip":"${remote_ip}","host":"${host}",` +
+			`"method":"${method}","uri":"${uri}","status":${status},"error":"${error}","latency":${latency},` +
+			`"latency_human":"${latency_human}","bytes_in":${bytes_in},` +
+			`"bytes_out":${bytes_out}}` + "\n",
+		CustomTimeFormat: "2006-01-02 15:04:05.00000",
+		Output:           os.Stdout,
+		colorer:          color.New(),
+	}
+)
+
+// Logger returns a middleware that logs HTTP requests.
+func Logger() echo.MiddlewareFunc {
+	return LoggerWithConfig(DefaultLoggerConfig)
+}
+
+// LoggerWithConfig returns a Logger middleware with config.
+// See: `Logger()`.
+func LoggerWithConfig(config LoggerConfig) echo.MiddlewareFunc {
+	// Defaults
+	if config.Skipper == nil {
+		config.Skipper = DefaultLoggerConfig.Skipper
+	}
+	if config.Format == "" {
+		config.Format = DefaultLoggerConfig.Format
+	}
+	if config.Output == nil {
+		config.Output = DefaultLoggerConfig.Output
+	}
+
+	config.template = fasttemplate.New(config.Format, "${", "}")
+	config.colorer = color.New()
+	config.colorer.SetOutput(config.Output)
+	config.pool = &sync.Pool{
+		New: func() interface{} {
+			return bytes.NewBuffer(make([]byte, 256))
+		},
+	}
+
+	return func(next echo.HandlerFunc) echo.HandlerFunc {
+		return func(c echo.Context) (err error) {
+			if config.Skipper(c) {
+				return next(c)
+			}
+
+			req := c.Request()
+			res := c.Response()
+			start := time.Now()
+			if err = next(c); err != nil {
+				c.Error(err)
+			}
+			stop := time.Now()
+			buf := config.pool.Get().(*bytes.Buffer)
+			buf.Reset()
+			defer config.pool.Put(buf)
+
+			if _, err = config.template.ExecuteFunc(buf, func(w io.Writer, tag string) (int, error) {
+				switch tag {
+				case "time_unix":
+					return buf.WriteString(strconv.FormatInt(time.Now().Unix(), 10))
+				case "time_unix_nano":
+					return buf.WriteString(strconv.FormatInt(time.Now().UnixNano(), 10))
+				case "time_rfc3339":
+					return buf.WriteString(time.Now().Format(time.RFC3339))
+				case "time_rfc3339_nano":
+					return buf.WriteString(time.Now().Format(time.RFC3339Nano))
+				case "time_custom":
+					return buf.WriteString(time.Now().Format(config.CustomTimeFormat))
+				case "id":
+					id := req.Header.Get(echo.HeaderXRequestID)
+					if id == "" {
+						id = res.Header().Get(echo.HeaderXRequestID)
+					}
+					return buf.WriteString(id)
+				case "remote_ip":
+					return buf.WriteString(c.RealIP())
+				case "host":
+					return buf.WriteString(req.Host)
+				case "uri":
+					return buf.WriteString(req.RequestURI)
+				case "method":
+					return buf.WriteString(req.Method)
+				case "path":
+					p := req.URL.Path
+					if p == "" {
+						p = "/"
+					}
+					return buf.WriteString(p)
+				case "protocol":
+					return buf.WriteString(req.Proto)
+				case "referer":
+					return buf.WriteString(req.Referer())
+				case "user_agent":
+					return buf.WriteString(req.UserAgent())
+				case "status":
+					n := res.Status
+					s := config.colorer.Green(n)
+					switch {
+					case n >= 500:
+						s = config.colorer.Red(n)
+					case n >= 400:
+						s = config.colorer.Yellow(n)
+					case n >= 300:
+						s = config.colorer.Cyan(n)
+					}
+					return buf.WriteString(s)
+				case "error":
+					if err != nil {
+						return buf.WriteString(err.Error())
+					}
+				case "latency":
+					l := stop.Sub(start)
+					return buf.WriteString(strconv.FormatInt(int64(l), 10))
+				case "latency_human":
+					return buf.WriteString(stop.Sub(start).String())
+				case "bytes_in":
+					cl := req.Header.Get(echo.HeaderContentLength)
+					if cl == "" {
+						cl = "0"
+					}
+					return buf.WriteString(cl)
+				case "bytes_out":
+					return buf.WriteString(strconv.FormatInt(res.Size, 10))
+				default:
+					switch {
+					case strings.HasPrefix(tag, "header:"):
+						return buf.Write([]byte(c.Request().Header.Get(tag[7:])))
+					case strings.HasPrefix(tag, "query:"):
+						return buf.Write([]byte(c.QueryParam(tag[6:])))
+					case strings.HasPrefix(tag, "form:"):
+						return buf.Write([]byte(c.FormValue(tag[5:])))
+					case strings.HasPrefix(tag, "cookie:"):
+						cookie, err := c.Cookie(tag[7:])
+						if err == nil {
+							return buf.Write([]byte(cookie.Value))
+						}
+					}
+				}
+				return 0, nil
+			}); err != nil {
+				return
+			}
+
+			_, err = config.Output.Write(buf.Bytes())
+			return
+		}
+	}
+}

+ 88 - 0
vendor/github.com/labstack/echo/middleware/method_override.go

@@ -0,0 +1,88 @@
+package middleware
+
+import "github.com/labstack/echo"
+
+type (
+	// MethodOverrideConfig defines the config for MethodOverride middleware.
+	MethodOverrideConfig struct {
+		// Skipper defines a function to skip middleware.
+		Skipper Skipper
+
+		// Getter is a function that gets overridden method from the request.
+		// Optional. Default values MethodFromHeader(echo.HeaderXHTTPMethodOverride).
+		Getter MethodOverrideGetter
+	}
+
+	// MethodOverrideGetter is a function that gets overridden method from the request
+	MethodOverrideGetter func(echo.Context) string
+)
+
+var (
+	// DefaultMethodOverrideConfig is the default MethodOverride middleware config.
+	DefaultMethodOverrideConfig = MethodOverrideConfig{
+		Skipper: DefaultSkipper,
+		Getter:  MethodFromHeader(echo.HeaderXHTTPMethodOverride),
+	}
+)
+
+// MethodOverride returns a MethodOverride middleware.
+// MethodOverride  middleware checks for the overridden method from the request and
+// uses it instead of the original method.
+//
+// For security reasons, only `POST` method can be overridden.
+func MethodOverride() echo.MiddlewareFunc {
+	return MethodOverrideWithConfig(DefaultMethodOverrideConfig)
+}
+
+// MethodOverrideWithConfig returns a MethodOverride middleware with config.
+// See: `MethodOverride()`.
+func MethodOverrideWithConfig(config MethodOverrideConfig) echo.MiddlewareFunc {
+	// Defaults
+	if config.Skipper == nil {
+		config.Skipper = DefaultMethodOverrideConfig.Skipper
+	}
+	if config.Getter == nil {
+		config.Getter = DefaultMethodOverrideConfig.Getter
+	}
+
+	return func(next echo.HandlerFunc) echo.HandlerFunc {
+		return func(c echo.Context) error {
+			if config.Skipper(c) {
+				return next(c)
+			}
+
+			req := c.Request()
+			if req.Method == echo.POST {
+				m := config.Getter(c)
+				if m != "" {
+					req.Method = m
+				}
+			}
+			return next(c)
+		}
+	}
+}
+
+// MethodFromHeader is a `MethodOverrideGetter` that gets overridden method from
+// the request header.
+func MethodFromHeader(header string) MethodOverrideGetter {
+	return func(c echo.Context) string {
+		return c.Request().Header.Get(header)
+	}
+}
+
+// MethodFromForm is a `MethodOverrideGetter` that gets overridden method from the
+// form parameter.
+func MethodFromForm(param string) MethodOverrideGetter {
+	return func(c echo.Context) string {
+		return c.FormValue(param)
+	}
+}
+
+// MethodFromQuery is a `MethodOverrideGetter` that gets overridden method from
+// the query parameter.
+func MethodFromQuery(param string) MethodOverrideGetter {
+	return func(c echo.Context) string {
+		return c.QueryParam(param)
+	}
+}

+ 38 - 0
vendor/github.com/labstack/echo/middleware/middleware.go

@@ -0,0 +1,38 @@
+package middleware
+
+import (
+	"regexp"
+	"strconv"
+	"strings"
+
+	"github.com/labstack/echo"
+)
+
+type (
+	// Skipper defines a function to skip middleware. Returning true skips processing
+	// the middleware.
+	Skipper func(echo.Context) bool
+
+	// BeforeFunc defines a function which is executed just before the middleware.
+	BeforeFunc func(echo.Context)
+)
+
+func captureTokens(pattern *regexp.Regexp, input string) *strings.Replacer {
+	groups := pattern.FindAllStringSubmatch(input, -1)
+	if groups == nil {
+		return nil
+	}
+	values := groups[0][1:]
+	replace := make([]string, 2*len(values))
+	for i, v := range values {
+		j := 2 * i
+		replace[j] = "$" + strconv.Itoa(i+1)
+		replace[j+1] = v
+	}
+	return strings.NewReplacer(replace...)
+}
+
+// DefaultSkipper returns false which processes the middleware.
+func DefaultSkipper(echo.Context) bool {
+	return false
+}

+ 252 - 0
vendor/github.com/labstack/echo/middleware/proxy.go

@@ -0,0 +1,252 @@
+package middleware
+
+import (
+	"fmt"
+	"io"
+	"math/rand"
+	"net"
+	"net/http"
+	"net/http/httputil"
+	"net/url"
+	"regexp"
+	"strings"
+	"sync"
+	"sync/atomic"
+	"time"
+
+	"github.com/labstack/echo"
+)
+
+// TODO: Handle TLS proxy
+
+type (
+	// ProxyConfig defines the config for Proxy middleware.
+	ProxyConfig struct {
+		// Skipper defines a function to skip middleware.
+		Skipper Skipper
+
+		// Balancer defines a load balancing technique.
+		// Required.
+		Balancer ProxyBalancer
+
+		// Rewrite defines URL path rewrite rules. The values captured in asterisk can be
+		// retrieved by index e.g. $1, $2 and so on.
+		// Examples:
+		// "/old":              "/new",
+		// "/api/*":            "/$1",
+		// "/js/*":             "/public/javascripts/$1",
+		// "/users/*/orders/*": "/user/$1/order/$2",
+		Rewrite map[string]string
+
+		rewriteRegex map[*regexp.Regexp]string
+	}
+
+	// ProxyTarget defines the upstream target.
+	ProxyTarget struct {
+		Name string
+		URL  *url.URL
+	}
+
+	// ProxyBalancer defines an interface to implement a load balancing technique.
+	ProxyBalancer interface {
+		AddTarget(*ProxyTarget) bool
+		RemoveTarget(string) bool
+		Next() *ProxyTarget
+	}
+
+	commonBalancer struct {
+		targets []*ProxyTarget
+		mutex   sync.RWMutex
+	}
+
+	// RandomBalancer implements a random load balancing technique.
+	randomBalancer struct {
+		*commonBalancer
+		random *rand.Rand
+	}
+
+	// RoundRobinBalancer implements a round-robin load balancing technique.
+	roundRobinBalancer struct {
+		*commonBalancer
+		i uint32
+	}
+)
+
+var (
+	// DefaultProxyConfig is the default Proxy middleware config.
+	DefaultProxyConfig = ProxyConfig{
+		Skipper: DefaultSkipper,
+	}
+)
+
+func proxyHTTP(t *ProxyTarget) http.Handler {
+	return httputil.NewSingleHostReverseProxy(t.URL)
+}
+
+func proxyRaw(t *ProxyTarget, c echo.Context) http.Handler {
+	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		in, _, err := c.Response().Hijack()
+		if err != nil {
+			c.Error(fmt.Errorf("proxy raw, hijack error=%v, url=%s", t.URL, err))
+			return
+		}
+		defer in.Close()
+
+		out, err := net.Dial("tcp", t.URL.Host)
+		if err != nil {
+			he := echo.NewHTTPError(http.StatusBadGateway, fmt.Sprintf("proxy raw, dial error=%v, url=%s", t.URL, err))
+			c.Error(he)
+			return
+		}
+		defer out.Close()
+
+		// Write header
+		err = r.Write(out)
+		if err != nil {
+			he := echo.NewHTTPError(http.StatusBadGateway, fmt.Sprintf("proxy raw, request header copy error=%v, url=%s", t.URL, err))
+			c.Error(he)
+			return
+		}
+
+		errCh := make(chan error, 2)
+		cp := func(dst io.Writer, src io.Reader) {
+			_, err = io.Copy(dst, src)
+			errCh <- err
+		}
+
+		go cp(out, in)
+		go cp(in, out)
+		err = <-errCh
+		if err != nil && err != io.EOF {
+			c.Logger().Errorf("proxy raw, copy body error=%v, url=%s", t.URL, err)
+		}
+	})
+}
+
+// NewRandomBalancer returns a random proxy balancer.
+func NewRandomBalancer(targets []*ProxyTarget) ProxyBalancer {
+	b := &randomBalancer{commonBalancer: new(commonBalancer)}
+	b.targets = targets
+	return b
+}
+
+// NewRoundRobinBalancer returns a round-robin proxy balancer.
+func NewRoundRobinBalancer(targets []*ProxyTarget) ProxyBalancer {
+	b := &roundRobinBalancer{commonBalancer: new(commonBalancer)}
+	b.targets = targets
+	return b
+}
+
+// AddTarget adds an upstream target to the list.
+func (b *commonBalancer) AddTarget(target *ProxyTarget) bool {
+	for _, t := range b.targets {
+		if t.Name == target.Name {
+			return false
+		}
+	}
+	b.mutex.Lock()
+	defer b.mutex.Unlock()
+	b.targets = append(b.targets, target)
+	return true
+}
+
+// RemoveTarget removes an upstream target from the list.
+func (b *commonBalancer) RemoveTarget(name string) bool {
+	b.mutex.Lock()
+	defer b.mutex.Unlock()
+	for i, t := range b.targets {
+		if t.Name == name {
+			b.targets = append(b.targets[:i], b.targets[i+1:]...)
+			return true
+		}
+	}
+	return false
+}
+
+// Next randomly returns an upstream target.
+func (b *randomBalancer) Next() *ProxyTarget {
+	if b.random == nil {
+		b.random = rand.New(rand.NewSource(int64(time.Now().Nanosecond())))
+	}
+	b.mutex.RLock()
+	defer b.mutex.RUnlock()
+	return b.targets[b.random.Intn(len(b.targets))]
+}
+
+// Next returns an upstream target using round-robin technique.
+func (b *roundRobinBalancer) Next() *ProxyTarget {
+	b.i = b.i % uint32(len(b.targets))
+	t := b.targets[b.i]
+	atomic.AddUint32(&b.i, 1)
+	return t
+}
+
+// Proxy returns a Proxy middleware.
+//
+// Proxy middleware forwards the request to upstream server using a configured load balancing technique.
+func Proxy(balancer ProxyBalancer) echo.MiddlewareFunc {
+	c := DefaultProxyConfig
+	c.Balancer = balancer
+	return ProxyWithConfig(c)
+}
+
+// ProxyWithConfig returns a Proxy middleware with config.
+// See: `Proxy()`
+func ProxyWithConfig(config ProxyConfig) echo.MiddlewareFunc {
+	// Defaults
+	if config.Skipper == nil {
+		config.Skipper = DefaultLoggerConfig.Skipper
+	}
+	if config.Balancer == nil {
+		panic("echo: proxy middleware requires balancer")
+	}
+	config.rewriteRegex = map[*regexp.Regexp]string{}
+
+	// Initialize
+	for k, v := range config.Rewrite {
+		k = strings.Replace(k, "*", "(\\S*)", -1)
+		config.rewriteRegex[regexp.MustCompile(k)] = v
+	}
+
+	return func(next echo.HandlerFunc) echo.HandlerFunc {
+		return func(c echo.Context) (err error) {
+			if config.Skipper(c) {
+				return next(c)
+			}
+
+			req := c.Request()
+			res := c.Response()
+			tgt := config.Balancer.Next()
+
+			// Rewrite
+			for k, v := range config.rewriteRegex {
+				replacer := captureTokens(k, req.URL.Path)
+				if replacer != nil {
+					req.URL.Path = replacer.Replace(v)
+				}
+			}
+
+			// Fix header
+			if req.Header.Get(echo.HeaderXRealIP) == "" {
+				req.Header.Set(echo.HeaderXRealIP, c.RealIP())
+			}
+			if req.Header.Get(echo.HeaderXForwardedProto) == "" {
+				req.Header.Set(echo.HeaderXForwardedProto, c.Scheme())
+			}
+			if c.IsWebSocket() && req.Header.Get(echo.HeaderXForwardedFor) == "" { // For HTTP, it is automatically set by Go HTTP reverse proxy.
+				req.Header.Set(echo.HeaderXForwardedFor, c.RealIP())
+			}
+
+			// Proxy
+			switch {
+			case c.IsWebSocket():
+				proxyRaw(tgt, c).ServeHTTP(res, req)
+			case req.Header.Get(echo.HeaderAccept) == "text/event-stream":
+			default:
+				proxyHTTP(tgt).ServeHTTP(res, req)
+			}
+
+			return
+		}
+	}
+}

+ 81 - 0
vendor/github.com/labstack/echo/middleware/recover.go

@@ -0,0 +1,81 @@
+package middleware
+
+import (
+	"fmt"
+	"runtime"
+
+	"github.com/labstack/echo"
+)
+
+type (
+	// RecoverConfig defines the config for Recover middleware.
+	RecoverConfig struct {
+		// Skipper defines a function to skip middleware.
+		Skipper Skipper
+
+		// Size of the stack to be printed.
+		// Optional. Default value 4KB.
+		StackSize int `yaml:"stack_size"`
+
+		// DisableStackAll disables formatting stack traces of all other goroutines
+		// into buffer after the trace for the current goroutine.
+		// Optional. Default value false.
+		DisableStackAll bool `yaml:"disable_stack_all"`
+
+		// DisablePrintStack disables printing stack trace.
+		// Optional. Default value as false.
+		DisablePrintStack bool `yaml:"disable_print_stack"`
+	}
+)
+
+var (
+	// DefaultRecoverConfig is the default Recover middleware config.
+	DefaultRecoverConfig = RecoverConfig{
+		Skipper:           DefaultSkipper,
+		StackSize:         4 << 10, // 4 KB
+		DisableStackAll:   false,
+		DisablePrintStack: false,
+	}
+)
+
+// Recover returns a middleware which recovers from panics anywhere in the chain
+// and handles the control to the centralized HTTPErrorHandler.
+func Recover() echo.MiddlewareFunc {
+	return RecoverWithConfig(DefaultRecoverConfig)
+}
+
+// RecoverWithConfig returns a Recover middleware with config.
+// See: `Recover()`.
+func RecoverWithConfig(config RecoverConfig) echo.MiddlewareFunc {
+	// Defaults
+	if config.Skipper == nil {
+		config.Skipper = DefaultRecoverConfig.Skipper
+	}
+	if config.StackSize == 0 {
+		config.StackSize = DefaultRecoverConfig.StackSize
+	}
+
+	return func(next echo.HandlerFunc) echo.HandlerFunc {
+		return func(c echo.Context) error {
+			if config.Skipper(c) {
+				return next(c)
+			}
+
+			defer func() {
+				if r := recover(); r != nil {
+					err, ok := r.(error)
+					if !ok {
+						err = fmt.Errorf("%v", r)
+					}
+					stack := make([]byte, config.StackSize)
+					length := runtime.Stack(stack, !config.DisableStackAll)
+					if !config.DisablePrintStack {
+						c.Logger().Printf("[PANIC RECOVER] %v %s\n", err, stack[:length])
+					}
+					c.Error(err)
+				}
+			}()
+			return next(c)
+		}
+	}
+}

+ 153 - 0
vendor/github.com/labstack/echo/middleware/redirect.go

@@ -0,0 +1,153 @@
+package middleware
+
+import (
+	"net/http"
+
+	"github.com/labstack/echo"
+)
+
+// RedirectConfig defines the config for Redirect middleware.
+type RedirectConfig struct {
+	// Skipper defines a function to skip middleware.
+	Skipper
+
+	// Status code to be used when redirecting the request.
+	// Optional. Default value http.StatusMovedPermanently.
+	Code int `yaml:"code"`
+}
+
+// redirectLogic represents a function that given a scheme, host and uri
+// can both: 1) determine if redirect is needed (will set ok accordingly) and
+// 2) return the appropriate redirect url.
+type redirectLogic func(scheme, host, uri string) (ok bool, url string)
+
+const www = "www"
+
+// DefaultRedirectConfig is the default Redirect middleware config.
+var DefaultRedirectConfig = RedirectConfig{
+	Skipper: DefaultSkipper,
+	Code:    http.StatusMovedPermanently,
+}
+
+// HTTPSRedirect redirects http requests to https.
+// For example, http://labstack.com will be redirect to https://labstack.com.
+//
+// Usage `Echo#Pre(HTTPSRedirect())`
+func HTTPSRedirect() echo.MiddlewareFunc {
+	return HTTPSRedirectWithConfig(DefaultRedirectConfig)
+}
+
+// HTTPSRedirectWithConfig returns an HTTPSRedirect middleware with config.
+// See `HTTPSRedirect()`.
+func HTTPSRedirectWithConfig(config RedirectConfig) echo.MiddlewareFunc {
+	return redirect(config, func(scheme, host, uri string) (ok bool, url string) {
+		if ok = scheme != "https"; ok {
+			url = "https://" + host + uri
+		}
+		return
+	})
+}
+
+// HTTPSWWWRedirect redirects http requests to https www.
+// For example, http://labstack.com will be redirect to https://www.labstack.com.
+//
+// Usage `Echo#Pre(HTTPSWWWRedirect())`
+func HTTPSWWWRedirect() echo.MiddlewareFunc {
+	return HTTPSWWWRedirectWithConfig(DefaultRedirectConfig)
+}
+
+// HTTPSWWWRedirectWithConfig returns an HTTPSRedirect middleware with config.
+// See `HTTPSWWWRedirect()`.
+func HTTPSWWWRedirectWithConfig(config RedirectConfig) echo.MiddlewareFunc {
+	return redirect(config, func(scheme, host, uri string) (ok bool, url string) {
+		if ok = scheme != "https" && host[:3] != www; ok {
+			url = "https://www." + host + uri
+		}
+		return
+	})
+}
+
+// HTTPSNonWWWRedirect redirects http requests to https non www.
+// For example, http://www.labstack.com will be redirect to https://labstack.com.
+//
+// Usage `Echo#Pre(HTTPSNonWWWRedirect())`
+func HTTPSNonWWWRedirect() echo.MiddlewareFunc {
+	return HTTPSNonWWWRedirectWithConfig(DefaultRedirectConfig)
+}
+
+// HTTPSNonWWWRedirectWithConfig returns an HTTPSRedirect middleware with config.
+// See `HTTPSNonWWWRedirect()`.
+func HTTPSNonWWWRedirectWithConfig(config RedirectConfig) echo.MiddlewareFunc {
+	return redirect(config, func(scheme, host, uri string) (ok bool, url string) {
+		if ok = scheme != "https"; ok {
+			if host[:3] == www {
+				host = host[4:]
+			}
+			url = "https://" + host + uri
+		}
+		return
+	})
+}
+
+// WWWRedirect redirects non www requests to www.
+// For example, http://labstack.com will be redirect to http://www.labstack.com.
+//
+// Usage `Echo#Pre(WWWRedirect())`
+func WWWRedirect() echo.MiddlewareFunc {
+	return WWWRedirectWithConfig(DefaultRedirectConfig)
+}
+
+// WWWRedirectWithConfig returns an HTTPSRedirect middleware with config.
+// See `WWWRedirect()`.
+func WWWRedirectWithConfig(config RedirectConfig) echo.MiddlewareFunc {
+	return redirect(config, func(scheme, host, uri string) (ok bool, url string) {
+		if ok = host[:3] != www; ok {
+			url = scheme + "://www." + host + uri
+		}
+		return
+	})
+}
+
+// NonWWWRedirect redirects www requests to non www.
+// For example, http://www.labstack.com will be redirect to http://labstack.com.
+//
+// Usage `Echo#Pre(NonWWWRedirect())`
+func NonWWWRedirect() echo.MiddlewareFunc {
+	return NonWWWRedirectWithConfig(DefaultRedirectConfig)
+}
+
+// NonWWWRedirectWithConfig returns an HTTPSRedirect middleware with config.
+// See `NonWWWRedirect()`.
+func NonWWWRedirectWithConfig(config RedirectConfig) echo.MiddlewareFunc {
+	return redirect(config, func(scheme, host, uri string) (ok bool, url string) {
+		if ok = host[:3] == www; ok {
+			url = scheme + "://" + host[4:] + uri
+		}
+		return
+	})
+}
+
+func redirect(config RedirectConfig, cb redirectLogic) echo.MiddlewareFunc {
+	if config.Skipper == nil {
+		config.Skipper = DefaultTrailingSlashConfig.Skipper
+	}
+	if config.Code == 0 {
+		config.Code = DefaultRedirectConfig.Code
+	}
+
+	return func(next echo.HandlerFunc) echo.HandlerFunc {
+		return func(c echo.Context) error {
+			if config.Skipper(c) {
+				return next(c)
+			}
+
+			req, scheme := c.Request(), c.Scheme()
+			host := req.Host
+			if ok, url := cb(scheme, host, req.RequestURI); ok {
+				return c.Redirect(config.Code, url)
+			}
+
+			return next(c)
+		}
+	}
+}

+ 64 - 0
vendor/github.com/labstack/echo/middleware/request_id.go

@@ -0,0 +1,64 @@
+package middleware
+
+import (
+	"github.com/labstack/echo"
+	"github.com/labstack/gommon/random"
+)
+
+type (
+	// RequestIDConfig defines the config for RequestID middleware.
+	RequestIDConfig struct {
+		// Skipper defines a function to skip middleware.
+		Skipper Skipper
+
+		// Generator defines a function to generate an ID.
+		// Optional. Default value random.String(32).
+		Generator func() string
+	}
+)
+
+var (
+	// DefaultRequestIDConfig is the default RequestID middleware config.
+	DefaultRequestIDConfig = RequestIDConfig{
+		Skipper:   DefaultSkipper,
+		Generator: generator,
+	}
+)
+
+// RequestID returns a X-Request-ID middleware.
+func RequestID() echo.MiddlewareFunc {
+	return RequestIDWithConfig(DefaultRequestIDConfig)
+}
+
+// RequestIDWithConfig returns a X-Request-ID middleware with config.
+func RequestIDWithConfig(config RequestIDConfig) echo.MiddlewareFunc {
+	// Defaults
+	if config.Skipper == nil {
+		config.Skipper = DefaultRequestIDConfig.Skipper
+	}
+	if config.Generator == nil {
+		config.Generator = generator
+	}
+
+	return func(next echo.HandlerFunc) echo.HandlerFunc {
+		return func(c echo.Context) error {
+			if config.Skipper(c) {
+				return next(c)
+			}
+
+			req := c.Request()
+			res := c.Response()
+			rid := req.Header.Get(echo.HeaderXRequestID)
+			if rid == "" {
+				rid = config.Generator()
+			}
+			res.Header().Set(echo.HeaderXRequestID, rid)
+
+			return next(c)
+		}
+	}
+}
+
+func generator() string {
+	return random.String(32)
+}

+ 84 - 0
vendor/github.com/labstack/echo/middleware/rewrite.go

@@ -0,0 +1,84 @@
+package middleware
+
+import (
+	"regexp"
+	"strings"
+
+	"github.com/labstack/echo"
+)
+
+type (
+	// RewriteConfig defines the config for Rewrite middleware.
+	RewriteConfig struct {
+		// Skipper defines a function to skip middleware.
+		Skipper Skipper
+
+		// Rules defines the URL path rewrite rules. The values captured in asterisk can be
+		// retrieved by index e.g. $1, $2 and so on.
+		// Example:
+		// "/old":              "/new",
+		// "/api/*":            "/$1",
+		// "/js/*":             "/public/javascripts/$1",
+		// "/users/*/orders/*": "/user/$1/order/$2",
+		// Required.
+		Rules map[string]string `yaml:"rules"`
+
+		rulesRegex map[*regexp.Regexp]string
+	}
+)
+
+var (
+	// DefaultRewriteConfig is the default Rewrite middleware config.
+	DefaultRewriteConfig = RewriteConfig{
+		Skipper: DefaultSkipper,
+	}
+)
+
+// Rewrite returns a Rewrite middleware.
+//
+// Rewrite middleware rewrites the URL path based on the provided rules.
+func Rewrite(rules map[string]string) echo.MiddlewareFunc {
+	c := DefaultRewriteConfig
+	c.Rules = rules
+	return RewriteWithConfig(c)
+}
+
+// RewriteWithConfig returns a Rewrite middleware with config.
+// See: `Rewrite()`.
+func RewriteWithConfig(config RewriteConfig) echo.MiddlewareFunc {
+	// Defaults
+	if config.Rules == nil {
+		panic("echo: rewrite middleware requires url path rewrite rules")
+	}
+	if config.Skipper == nil {
+		config.Skipper = DefaultBodyDumpConfig.Skipper
+	}
+	config.rulesRegex = map[*regexp.Regexp]string{}
+
+	// Initialize
+	for k, v := range config.Rules {
+		k = strings.Replace(k, "*", "(.*)", -1)
+		k = k + "$"
+		config.rulesRegex[regexp.MustCompile(k)] = v
+	}
+
+	return func(next echo.HandlerFunc) echo.HandlerFunc {
+		return func(c echo.Context) (err error) {
+			if config.Skipper(c) {
+				return next(c)
+			}
+
+			req := c.Request()
+
+			// Rewrite
+			for k, v := range config.rulesRegex {
+				replacer := captureTokens(k, req.URL.Path)
+				if replacer != nil {
+					req.URL.Path = replacer.Replace(v)
+					break
+				}
+			}
+			return next(c)
+		}
+	}
+}

+ 116 - 0
vendor/github.com/labstack/echo/middleware/secure.go

@@ -0,0 +1,116 @@
+package middleware
+
+import (
+	"fmt"
+
+	"github.com/labstack/echo"
+)
+
+type (
+	// SecureConfig defines the config for Secure middleware.
+	SecureConfig struct {
+		// Skipper defines a function to skip middleware.
+		Skipper Skipper
+
+		// XSSProtection provides protection against cross-site scripting attack (XSS)
+		// by setting the `X-XSS-Protection` header.
+		// Optional. Default value "1; mode=block".
+		XSSProtection string `yaml:"xss_protection"`
+
+		// ContentTypeNosniff provides protection against overriding Content-Type
+		// header by setting the `X-Content-Type-Options` header.
+		// Optional. Default value "nosniff".
+		ContentTypeNosniff string `yaml:"content_type_nosniff"`
+
+		// XFrameOptions can be used to indicate whether or not a browser should
+		// be allowed to render a page in a <frame>, <iframe> or <object> .
+		// Sites can use this to avoid clickjacking attacks, by ensuring that their
+		// content is not embedded into other sites.provides protection against
+		// clickjacking.
+		// Optional. Default value "SAMEORIGIN".
+		// Possible values:
+		// - "SAMEORIGIN" - The page can only be displayed in a frame on the same origin as the page itself.
+		// - "DENY" - The page cannot be displayed in a frame, regardless of the site attempting to do so.
+		// - "ALLOW-FROM uri" - The page can only be displayed in a frame on the specified origin.
+		XFrameOptions string `yaml:"x_frame_options"`
+
+		// HSTSMaxAge sets the `Strict-Transport-Security` header to indicate how
+		// long (in seconds) browsers should remember that this site is only to
+		// be accessed using HTTPS. This reduces your exposure to some SSL-stripping
+		// man-in-the-middle (MITM) attacks.
+		// Optional. Default value 0.
+		HSTSMaxAge int `yaml:"hsts_max_age"`
+
+		// HSTSExcludeSubdomains won't include subdomains tag in the `Strict Transport Security`
+		// header, excluding all subdomains from security policy. It has no effect
+		// unless HSTSMaxAge is set to a non-zero value.
+		// Optional. Default value false.
+		HSTSExcludeSubdomains bool `yaml:"hsts_exclude_subdomains"`
+
+		// ContentSecurityPolicy sets the `Content-Security-Policy` header providing
+		// security against cross-site scripting (XSS), clickjacking and other code
+		// injection attacks resulting from execution of malicious content in the
+		// trusted web page context.
+		// Optional. Default value "".
+		ContentSecurityPolicy string `yaml:"content_security_policy"`
+	}
+)
+
+var (
+	// DefaultSecureConfig is the default Secure middleware config.
+	DefaultSecureConfig = SecureConfig{
+		Skipper:            DefaultSkipper,
+		XSSProtection:      "1; mode=block",
+		ContentTypeNosniff: "nosniff",
+		XFrameOptions:      "SAMEORIGIN",
+	}
+)
+
+// Secure returns a Secure middleware.
+// Secure middleware provides protection against cross-site scripting (XSS) attack,
+// content type sniffing, clickjacking, insecure connection and other code injection
+// attacks.
+func Secure() echo.MiddlewareFunc {
+	return SecureWithConfig(DefaultSecureConfig)
+}
+
+// SecureWithConfig returns a Secure middleware with config.
+// See: `Secure()`.
+func SecureWithConfig(config SecureConfig) echo.MiddlewareFunc {
+	// Defaults
+	if config.Skipper == nil {
+		config.Skipper = DefaultSecureConfig.Skipper
+	}
+
+	return func(next echo.HandlerFunc) echo.HandlerFunc {
+		return func(c echo.Context) error {
+			if config.Skipper(c) {
+				return next(c)
+			}
+
+			req := c.Request()
+			res := c.Response()
+
+			if config.XSSProtection != "" {
+				res.Header().Set(echo.HeaderXXSSProtection, config.XSSProtection)
+			}
+			if config.ContentTypeNosniff != "" {
+				res.Header().Set(echo.HeaderXContentTypeOptions, config.ContentTypeNosniff)
+			}
+			if config.XFrameOptions != "" {
+				res.Header().Set(echo.HeaderXFrameOptions, config.XFrameOptions)
+			}
+			if (c.IsTLS() || (req.Header.Get(echo.HeaderXForwardedProto) == "https")) && config.HSTSMaxAge != 0 {
+				subdomains := ""
+				if !config.HSTSExcludeSubdomains {
+					subdomains = "; includeSubdomains"
+				}
+				res.Header().Set(echo.HeaderStrictTransportSecurity, fmt.Sprintf("max-age=%d%s", config.HSTSMaxAge, subdomains))
+			}
+			if config.ContentSecurityPolicy != "" {
+				res.Header().Set(echo.HeaderContentSecurityPolicy, config.ContentSecurityPolicy)
+			}
+			return next(c)
+		}
+	}
+}

+ 119 - 0
vendor/github.com/labstack/echo/middleware/slash.go

@@ -0,0 +1,119 @@
+package middleware
+
+import (
+	"github.com/labstack/echo"
+)
+
+type (
+	// TrailingSlashConfig defines the config for TrailingSlash middleware.
+	TrailingSlashConfig struct {
+		// Skipper defines a function to skip middleware.
+		Skipper Skipper
+
+		// Status code to be used when redirecting the request.
+		// Optional, but when provided the request is redirected using this code.
+		RedirectCode int `yaml:"redirect_code"`
+	}
+)
+
+var (
+	// DefaultTrailingSlashConfig is the default TrailingSlash middleware config.
+	DefaultTrailingSlashConfig = TrailingSlashConfig{
+		Skipper: DefaultSkipper,
+	}
+)
+
+// AddTrailingSlash returns a root level (before router) middleware which adds a
+// trailing slash to the request `URL#Path`.
+//
+// Usage `Echo#Pre(AddTrailingSlash())`
+func AddTrailingSlash() echo.MiddlewareFunc {
+	return AddTrailingSlashWithConfig(DefaultTrailingSlashConfig)
+}
+
+// AddTrailingSlashWithConfig returns a AddTrailingSlash middleware with config.
+// See `AddTrailingSlash()`.
+func AddTrailingSlashWithConfig(config TrailingSlashConfig) echo.MiddlewareFunc {
+	// Defaults
+	if config.Skipper == nil {
+		config.Skipper = DefaultTrailingSlashConfig.Skipper
+	}
+
+	return func(next echo.HandlerFunc) echo.HandlerFunc {
+		return func(c echo.Context) error {
+			if config.Skipper(c) {
+				return next(c)
+			}
+
+			req := c.Request()
+			url := req.URL
+			path := url.Path
+			qs := c.QueryString()
+			if path != "/" && path[len(path)-1] != '/' {
+				path += "/"
+				uri := path
+				if qs != "" {
+					uri += "?" + qs
+				}
+
+				// Redirect
+				if config.RedirectCode != 0 {
+					return c.Redirect(config.RedirectCode, uri)
+				}
+
+				// Forward
+				req.RequestURI = uri
+				url.Path = path
+			}
+			return next(c)
+		}
+	}
+}
+
+// RemoveTrailingSlash returns a root level (before router) middleware which removes
+// a trailing slash from the request URI.
+//
+// Usage `Echo#Pre(RemoveTrailingSlash())`
+func RemoveTrailingSlash() echo.MiddlewareFunc {
+	return RemoveTrailingSlashWithConfig(TrailingSlashConfig{})
+}
+
+// RemoveTrailingSlashWithConfig returns a RemoveTrailingSlash middleware with config.
+// See `RemoveTrailingSlash()`.
+func RemoveTrailingSlashWithConfig(config TrailingSlashConfig) echo.MiddlewareFunc {
+	// Defaults
+	if config.Skipper == nil {
+		config.Skipper = DefaultTrailingSlashConfig.Skipper
+	}
+
+	return func(next echo.HandlerFunc) echo.HandlerFunc {
+		return func(c echo.Context) error {
+			if config.Skipper(c) {
+				return next(c)
+			}
+
+			req := c.Request()
+			url := req.URL
+			path := url.Path
+			qs := c.QueryString()
+			l := len(path) - 1
+			if l >= 0 && path != "/" && path[l] == '/' {
+				path = path[:l]
+				uri := path
+				if qs != "" {
+					uri += "?" + qs
+				}
+
+				// Redirect
+				if config.RedirectCode != 0 {
+					return c.Redirect(config.RedirectCode, uri)
+				}
+
+				// Forward
+				req.RequestURI = uri
+				url.Path = path
+			}
+			return next(c)
+		}
+	}
+}

+ 229 - 0
vendor/github.com/labstack/echo/middleware/static.go

@@ -0,0 +1,229 @@
+package middleware
+
+import (
+	"fmt"
+	"html/template"
+	"net/http"
+	"net/url"
+	"os"
+	"path"
+	"path/filepath"
+	"strings"
+
+	"github.com/labstack/echo"
+	"github.com/labstack/gommon/bytes"
+)
+
+type (
+	// StaticConfig defines the config for Static middleware.
+	StaticConfig struct {
+		// Skipper defines a function to skip middleware.
+		Skipper Skipper
+
+		// Root directory from where the static content is served.
+		// Required.
+		Root string `yaml:"root"`
+
+		// Index file for serving a directory.
+		// Optional. Default value "index.html".
+		Index string `yaml:"index"`
+
+		// Enable HTML5 mode by forwarding all not-found requests to root so that
+		// SPA (single-page application) can handle the routing.
+		// Optional. Default value false.
+		HTML5 bool `yaml:"html5"`
+
+		// Enable directory browsing.
+		// Optional. Default value false.
+		Browse bool `yaml:"browse"`
+	}
+)
+
+const html = `
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0">
+  <meta http-equiv="X-UA-Compatible" content="ie=edge">
+  <title>{{ .Name }}</title>
+  <style>
+    body {
+			font-family: Menlo, Consolas, monospace;
+			padding: 48px;
+		}
+		header {
+			padding: 4px 16px;
+			font-size: 24px;
+		}
+    ul {
+			list-style-type: none;
+			margin: 0;
+    	padding: 20px 0 0 0;
+			display: flex;
+			flex-wrap: wrap;
+    }
+    li {
+			width: 300px;
+			padding: 16px;
+		}
+		li a {
+			display: block;
+			overflow: hidden;
+			white-space: nowrap;
+			text-overflow: ellipsis;
+			text-decoration: none;
+			transition: opacity 0.25s;
+		}
+		li span {
+			color: #707070; 
+			font-size: 12px;
+		}
+		li a:hover {
+			opacity: 0.50;
+		}
+		.dir {
+			color: #E91E63;
+		}
+		.file {
+			color: #673AB7;
+		}
+  </style>
+</head>
+<body>
+	<header>
+		{{ .Name }}
+	</header>
+	<ul>
+		{{ range .Files }}
+		<li>
+		{{ if .Dir }}
+			{{ $name := print .Name "/" }}
+			<a class="dir" href="{{ $name }}">{{ $name }}</a>
+			{{ else }}
+			<a class="file" href="{{ .Name }}">{{ .Name }}</a>
+			<span>{{ .Size }}</span>
+		{{ end }}
+		</li>
+		{{ end }}
+  </ul>
+</body>
+</html>
+`
+
+var (
+	// DefaultStaticConfig is the default Static middleware config.
+	DefaultStaticConfig = StaticConfig{
+		Skipper: DefaultSkipper,
+		Index:   "index.html",
+	}
+)
+
+// Static returns a Static middleware to serves static content from the provided
+// root directory.
+func Static(root string) echo.MiddlewareFunc {
+	c := DefaultStaticConfig
+	c.Root = root
+	return StaticWithConfig(c)
+}
+
+// StaticWithConfig returns a Static middleware with config.
+// See `Static()`.
+func StaticWithConfig(config StaticConfig) echo.MiddlewareFunc {
+	// Defaults
+	if config.Root == "" {
+		config.Root = "." // For security we want to restrict to CWD.
+	}
+	if config.Skipper == nil {
+		config.Skipper = DefaultStaticConfig.Skipper
+	}
+	if config.Index == "" {
+		config.Index = DefaultStaticConfig.Index
+	}
+
+	// Index template
+	t, err := template.New("index").Parse(html)
+	if err != nil {
+		panic(fmt.Sprintf("echo: %v", err))
+	}
+
+	return func(next echo.HandlerFunc) echo.HandlerFunc {
+		return func(c echo.Context) (err error) {
+			if config.Skipper(c) {
+				return next(c)
+			}
+
+			p := c.Request().URL.Path
+			if strings.HasSuffix(c.Path(), "*") { // When serving from a group, e.g. `/static*`.
+				p = c.Param("*")
+			}
+			p, err = url.PathUnescape(p)
+			if err != nil {
+				return
+			}
+			name := filepath.Join(config.Root, path.Clean("/"+p)) // "/"+ for security
+
+			fi, err := os.Stat(name)
+			if err != nil {
+				if os.IsNotExist(err) {
+					if err = next(c); err != nil {
+						if he, ok := err.(*echo.HTTPError); ok {
+							if config.HTML5 && he.Code == http.StatusNotFound {
+								return c.File(filepath.Join(config.Root, config.Index))
+							}
+						}
+						return
+					}
+				}
+				return
+			}
+
+			if fi.IsDir() {
+				index := filepath.Join(name, config.Index)
+				fi, err = os.Stat(index)
+
+				if err != nil {
+					if config.Browse {
+						return listDir(t, name, c.Response())
+					}
+					if os.IsNotExist(err) {
+						return next(c)
+					}
+					return
+				}
+
+				return c.File(index)
+			}
+
+			return c.File(name)
+		}
+	}
+}
+
+func listDir(t *template.Template, name string, res *echo.Response) (err error) {
+	file, err := os.Open(name)
+	if err != nil {
+		return
+	}
+	files, err := file.Readdir(-1)
+	if err != nil {
+		return
+	}
+
+	// Create directory index
+	res.Header().Set(echo.HeaderContentType, echo.MIMETextHTMLCharsetUTF8)
+	data := struct {
+		Name  string
+		Files []interface{}
+	}{
+		Name: name,
+	}
+	for _, f := range files {
+		data.Files = append(data.Files, struct {
+			Name string
+			Dir  bool
+			Size string
+		}{f.Name(), f.IsDir(), bytes.Format(f.Size())})
+	}
+	return t.Execute(res, data)
+}

+ 110 - 0
vendor/github.com/labstack/echo/response.go

@@ -0,0 +1,110 @@
+package echo
+
+import (
+	"bufio"
+	"net"
+	"net/http"
+)
+
+type (
+	// Response wraps an http.ResponseWriter and implements its interface to be used
+	// by an HTTP handler to construct an HTTP response.
+	// See: https://golang.org/pkg/net/http/#ResponseWriter
+	Response struct {
+		echo        *Echo
+		beforeFuncs []func()
+		afterFuncs  []func()
+		Writer      http.ResponseWriter
+		Status      int
+		Size        int64
+		Committed   bool
+	}
+)
+
+// NewResponse creates a new instance of Response.
+func NewResponse(w http.ResponseWriter, e *Echo) (r *Response) {
+	return &Response{Writer: w, echo: e}
+}
+
+// Header returns the header map for the writer that will be sent by
+// WriteHeader. Changing the header after a call to WriteHeader (or Write) has
+// no effect unless the modified headers were declared as trailers by setting
+// the "Trailer" header before the call to WriteHeader (see example)
+// To suppress implicit response headers, set their value to nil.
+// Example: https://golang.org/pkg/net/http/#example_ResponseWriter_trailers
+func (r *Response) Header() http.Header {
+	return r.Writer.Header()
+}
+
+// Before registers a function which is called just before the response is written.
+func (r *Response) Before(fn func()) {
+	r.beforeFuncs = append(r.beforeFuncs, fn)
+}
+
+// After registers a function which is called just after the response is written.
+// If the `Content-Length` is unknown, none of the after function is executed.
+func (r *Response) After(fn func()) {
+	r.afterFuncs = append(r.afterFuncs, fn)
+}
+
+// WriteHeader sends an HTTP response header with status code. If WriteHeader is
+// not called explicitly, the first call to Write will trigger an implicit
+// WriteHeader(http.StatusOK). Thus explicit calls to WriteHeader are mainly
+// used to send error codes.
+func (r *Response) WriteHeader(code int) {
+	if r.Committed {
+		r.echo.Logger.Warn("response already committed")
+		return
+	}
+	for _, fn := range r.beforeFuncs {
+		fn()
+	}
+	r.Status = code
+	r.Writer.WriteHeader(code)
+	r.Committed = true
+}
+
+// Write writes the data to the connection as part of an HTTP reply.
+func (r *Response) Write(b []byte) (n int, err error) {
+	if !r.Committed {
+		r.WriteHeader(http.StatusOK)
+	}
+	n, err = r.Writer.Write(b)
+	r.Size += int64(n)
+	for _, fn := range r.afterFuncs {
+		fn()
+	}
+	return
+}
+
+// Flush implements the http.Flusher interface to allow an HTTP handler to flush
+// buffered data to the client.
+// See [http.Flusher](https://golang.org/pkg/net/http/#Flusher)
+func (r *Response) Flush() {
+	r.Writer.(http.Flusher).Flush()
+}
+
+// Hijack implements the http.Hijacker interface to allow an HTTP handler to
+// take over the connection.
+// See [http.Hijacker](https://golang.org/pkg/net/http/#Hijacker)
+func (r *Response) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+	return r.Writer.(http.Hijacker).Hijack()
+}
+
+// CloseNotify implements the http.CloseNotifier interface to allow detecting
+// when the underlying connection has gone away.
+// This mechanism can be used to cancel long operations on the server if the
+// client has disconnected before the response is ready.
+// See [http.CloseNotifier](https://golang.org/pkg/net/http/#CloseNotifier)
+func (r *Response) CloseNotify() <-chan bool {
+	return r.Writer.(http.CloseNotifier).CloseNotify()
+}
+
+func (r *Response) reset(w http.ResponseWriter) {
+	r.beforeFuncs = nil
+	r.afterFuncs = nil
+	r.Writer = w
+	r.Size = 0
+	r.Status = http.StatusOK
+	r.Committed = false
+}

+ 434 - 0
vendor/github.com/labstack/echo/router.go

@@ -0,0 +1,434 @@
+package echo
+
+type (
+	// Router is the registry of all registered routes for an `Echo` instance for
+	// request matching and URL path parameter parsing.
+	Router struct {
+		tree   *node
+		routes map[string]*Route
+		echo   *Echo
+	}
+	node struct {
+		kind          kind
+		label         byte
+		prefix        string
+		parent        *node
+		children      children
+		ppath         string
+		pnames        []string
+		methodHandler *methodHandler
+	}
+	kind          uint8
+	children      []*node
+	methodHandler struct {
+		connect  HandlerFunc
+		delete   HandlerFunc
+		get      HandlerFunc
+		head     HandlerFunc
+		options  HandlerFunc
+		patch    HandlerFunc
+		post     HandlerFunc
+		propfind HandlerFunc
+		put      HandlerFunc
+		trace    HandlerFunc
+	}
+)
+
+const (
+	skind kind = iota
+	pkind
+	akind
+)
+
+// NewRouter returns a new Router instance.
+func NewRouter(e *Echo) *Router {
+	return &Router{
+		tree: &node{
+			methodHandler: new(methodHandler),
+		},
+		routes: map[string]*Route{},
+		echo:   e,
+	}
+}
+
+// Add registers a new route for method and path with matching handler.
+func (r *Router) Add(method, path string, h HandlerFunc) {
+	// Validate path
+	if path == "" {
+		panic("echo: path cannot be empty")
+	}
+	if path[0] != '/' {
+		path = "/" + path
+	}
+	pnames := []string{} // Param names
+	ppath := path        // Pristine path
+
+	for i, l := 0, len(path); i < l; i++ {
+		if path[i] == ':' {
+			j := i + 1
+
+			r.insert(method, path[:i], nil, skind, "", nil)
+			for ; i < l && path[i] != '/'; i++ {
+			}
+
+			pnames = append(pnames, path[j:i])
+			path = path[:j] + path[i:]
+			i, l = j, len(path)
+
+			if i == l {
+				r.insert(method, path[:i], h, pkind, ppath, pnames)
+				return
+			}
+			r.insert(method, path[:i], nil, pkind, ppath, pnames)
+		} else if path[i] == '*' {
+			r.insert(method, path[:i], nil, skind, "", nil)
+			pnames = append(pnames, "*")
+			r.insert(method, path[:i+1], h, akind, ppath, pnames)
+			return
+		}
+	}
+
+	r.insert(method, path, h, skind, ppath, pnames)
+}
+
+func (r *Router) insert(method, path string, h HandlerFunc, t kind, ppath string, pnames []string) {
+	// Adjust max param
+	l := len(pnames)
+	if *r.echo.maxParam < l {
+		*r.echo.maxParam = l
+	}
+
+	cn := r.tree // Current node as root
+	if cn == nil {
+		panic("echo: invalid method")
+	}
+	search := path
+
+	for {
+		sl := len(search)
+		pl := len(cn.prefix)
+		l := 0
+
+		// LCP
+		max := pl
+		if sl < max {
+			max = sl
+		}
+		for ; l < max && search[l] == cn.prefix[l]; l++ {
+		}
+
+		if l == 0 {
+			// At root node
+			cn.label = search[0]
+			cn.prefix = search
+			if h != nil {
+				cn.kind = t
+				cn.addHandler(method, h)
+				cn.ppath = ppath
+				cn.pnames = pnames
+			}
+		} else if l < pl {
+			// Split node
+			n := newNode(cn.kind, cn.prefix[l:], cn, cn.children, cn.methodHandler, cn.ppath, cn.pnames)
+
+			// Reset parent node
+			cn.kind = skind
+			cn.label = cn.prefix[0]
+			cn.prefix = cn.prefix[:l]
+			cn.children = nil
+			cn.methodHandler = new(methodHandler)
+			cn.ppath = ""
+			cn.pnames = nil
+
+			cn.addChild(n)
+
+			if l == sl {
+				// At parent node
+				cn.kind = t
+				cn.addHandler(method, h)
+				cn.ppath = ppath
+				cn.pnames = pnames
+			} else {
+				// Create child node
+				n = newNode(t, search[l:], cn, nil, new(methodHandler), ppath, pnames)
+				n.addHandler(method, h)
+				cn.addChild(n)
+			}
+		} else if l < sl {
+			search = search[l:]
+			c := cn.findChildWithLabel(search[0])
+			if c != nil {
+				// Go deeper
+				cn = c
+				continue
+			}
+			// Create child node
+			n := newNode(t, search, cn, nil, new(methodHandler), ppath, pnames)
+			n.addHandler(method, h)
+			cn.addChild(n)
+		} else {
+			// Node already exists
+			if h != nil {
+				cn.addHandler(method, h)
+				cn.ppath = ppath
+				if len(cn.pnames) == 0 { // Issue #729
+					cn.pnames = pnames
+				}
+			}
+		}
+		return
+	}
+}
+
+func newNode(t kind, pre string, p *node, c children, mh *methodHandler, ppath string, pnames []string) *node {
+	return &node{
+		kind:          t,
+		label:         pre[0],
+		prefix:        pre,
+		parent:        p,
+		children:      c,
+		ppath:         ppath,
+		pnames:        pnames,
+		methodHandler: mh,
+	}
+}
+
+func (n *node) addChild(c *node) {
+	n.children = append(n.children, c)
+}
+
+func (n *node) findChild(l byte, t kind) *node {
+	for _, c := range n.children {
+		if c.label == l && c.kind == t {
+			return c
+		}
+	}
+	return nil
+}
+
+func (n *node) findChildWithLabel(l byte) *node {
+	for _, c := range n.children {
+		if c.label == l {
+			return c
+		}
+	}
+	return nil
+}
+
+func (n *node) findChildByKind(t kind) *node {
+	for _, c := range n.children {
+		if c.kind == t {
+			return c
+		}
+	}
+	return nil
+}
+
+func (n *node) addHandler(method string, h HandlerFunc) {
+	switch method {
+	case CONNECT:
+		n.methodHandler.connect = h
+	case DELETE:
+		n.methodHandler.delete = h
+	case GET:
+		n.methodHandler.get = h
+	case HEAD:
+		n.methodHandler.head = h
+	case OPTIONS:
+		n.methodHandler.options = h
+	case PATCH:
+		n.methodHandler.patch = h
+	case POST:
+		n.methodHandler.post = h
+	case PROPFIND:
+		n.methodHandler.propfind = h
+	case PUT:
+		n.methodHandler.put = h
+	case TRACE:
+		n.methodHandler.trace = h
+	}
+}
+
+func (n *node) findHandler(method string) HandlerFunc {
+	switch method {
+	case CONNECT:
+		return n.methodHandler.connect
+	case DELETE:
+		return n.methodHandler.delete
+	case GET:
+		return n.methodHandler.get
+	case HEAD:
+		return n.methodHandler.head
+	case OPTIONS:
+		return n.methodHandler.options
+	case PATCH:
+		return n.methodHandler.patch
+	case POST:
+		return n.methodHandler.post
+	case PROPFIND:
+		return n.methodHandler.propfind
+	case PUT:
+		return n.methodHandler.put
+	case TRACE:
+		return n.methodHandler.trace
+	default:
+		return nil
+	}
+}
+
+func (n *node) checkMethodNotAllowed() HandlerFunc {
+	for _, m := range methods {
+		if h := n.findHandler(m); h != nil {
+			return MethodNotAllowedHandler
+		}
+	}
+	return NotFoundHandler
+}
+
+// Find lookup a handler registered for method and path. It also parses URL for path
+// parameters and load them into context.
+//
+// For performance:
+//
+// - Get context from `Echo#AcquireContext()`
+// - Reset it `Context#Reset()`
+// - Return it `Echo#ReleaseContext()`.
+func (r *Router) Find(method, path string, c Context) {
+	ctx := c.(*context)
+	ctx.path = path
+	cn := r.tree // Current node as root
+
+	var (
+		search  = path
+		child   *node         // Child node
+		n       int           // Param counter
+		nk      kind          // Next kind
+		nn      *node         // Next node
+		ns      string        // Next search
+		pvalues = ctx.pvalues // Use the internal slice so the interface can keep the illusion of a dynamic slice
+	)
+
+	// Search order static > param > any
+	for {
+		if search == "" {
+			goto End
+		}
+
+		pl := 0 // Prefix length
+		l := 0  // LCP length
+
+		if cn.label != ':' {
+			sl := len(search)
+			pl = len(cn.prefix)
+
+			// LCP
+			max := pl
+			if sl < max {
+				max = sl
+			}
+			for ; l < max && search[l] == cn.prefix[l]; l++ {
+			}
+		}
+
+		if l == pl {
+			// Continue search
+			search = search[l:]
+		} else {
+			cn = nn
+			search = ns
+			if nk == pkind {
+				goto Param
+			} else if nk == akind {
+				goto Any
+			}
+			// Not found
+			return
+		}
+
+		if search == "" {
+			goto End
+		}
+
+		// Static node
+		if child = cn.findChild(search[0], skind); child != nil {
+			// Save next
+			if cn.prefix[len(cn.prefix)-1] == '/' { // Issue #623
+				nk = pkind
+				nn = cn
+				ns = search
+			}
+			cn = child
+			continue
+		}
+
+		// Param node
+	Param:
+		if child = cn.findChildByKind(pkind); child != nil {
+			// Issue #378
+			if len(pvalues) == n {
+				continue
+			}
+
+			// Save next
+			if cn.prefix[len(cn.prefix)-1] == '/' { // Issue #623
+				nk = akind
+				nn = cn
+				ns = search
+			}
+
+			cn = child
+			i, l := 0, len(search)
+			for ; i < l && search[i] != '/'; i++ {
+			}
+			pvalues[n] = search[:i]
+			n++
+			search = search[i:]
+			continue
+		}
+
+		// Any node
+	Any:
+		if cn = cn.findChildByKind(akind); cn == nil {
+			if nn != nil {
+				cn = nn
+				nn = cn.parent // Next (Issue #954)
+				search = ns
+				if nk == pkind {
+					goto Param
+				} else if nk == akind {
+					goto Any
+				}
+			}
+			// Not found
+			return
+		}
+		pvalues[len(cn.pnames)-1] = search
+		goto End
+	}
+
+End:
+	ctx.handler = cn.findHandler(method)
+	ctx.path = cn.ppath
+	ctx.pnames = cn.pnames
+
+	// NOTE: Slow zone...
+	if ctx.handler == nil {
+		ctx.handler = cn.checkMethodNotAllowed()
+
+		// Dig further for any, might have an empty value for *, e.g.
+		// serving a directory. Issue #207.
+		if cn = cn.findChildByKind(akind); cn == nil {
+			return
+		}
+		if h := cn.findHandler(method); h != nil {
+			ctx.handler = h
+		} else {
+			ctx.handler = cn.checkMethodNotAllowed()
+		}
+		ctx.path = cn.ppath
+		ctx.pnames = cn.pnames
+		pvalues[len(cn.pnames)-1] = ""
+	}
+
+	return
+}

+ 22 - 0
vendor/github.com/labstack/gommon/LICENSE

@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 labstack
+
+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.
+

+ 29 - 0
vendor/github.com/labstack/gommon/bytes/README.md

@@ -0,0 +1,29 @@
+# Bytes
+
+- Format bytes integer to human readable bytes string.
+- Parse human readable bytes string to bytes integer.
+
+## Installation
+
+```go
+go get github.com/labstack/gommon/bytes
+```
+
+## [Usage](https://github.com/labstack/gommon/blob/master/bytes/bytes_test.go)
+
+### Format
+
+```go
+println(bytes.Format(13231323))
+```
+
+`12.62MB`
+
+### Parse
+
+```go
+b, _ = Parse("2M")
+println(b)
+```
+
+`2097152`

+ 108 - 0
vendor/github.com/labstack/gommon/bytes/bytes.go

@@ -0,0 +1,108 @@
+package bytes
+
+import (
+	"fmt"
+	"regexp"
+	"strconv"
+)
+
+type (
+	// Bytes struct
+	Bytes struct{}
+)
+
+const (
+	_ = 1.0 << (10 * iota) // ignore first value by assigning to blank identifier
+	KB
+	MB
+	GB
+	TB
+	PB
+	EB
+)
+
+var (
+	pattern = regexp.MustCompile(`(?i)^(-?\d+(?:\.\d+)?)([KMGTPE]B?|B?)$`)
+	global  = New()
+)
+
+// New creates a Bytes instance.
+func New() *Bytes {
+	return &Bytes{}
+}
+
+// Format formats bytes integer to human readable string.
+// For example, 31323 bytes will return 30.59KB.
+func (*Bytes) Format(b int64) string {
+	multiple := ""
+	value := float64(b)
+
+	switch {
+	case b >= EB:
+		value /= EB
+		multiple = "EB"
+	case b >= PB:
+		value /= PB
+		multiple = "PB"
+	case b >= TB:
+		value /= TB
+		multiple = "TB"
+	case b >= GB:
+		value /= GB
+		multiple = "GB"
+	case b >= MB:
+		value /= MB
+		multiple = "MB"
+	case b >= KB:
+		value /= KB
+		multiple = "KB"
+	case b == 0:
+		return "0"
+	default:
+		return strconv.FormatInt(b, 10) + "B"
+	}
+
+	return fmt.Sprintf("%.2f%s", value, multiple)
+}
+
+// Parse parses human readable bytes string to bytes integer.
+// For example, 6GB (6G is also valid) will return 6442450944.
+func (*Bytes) Parse(value string) (i int64, err error) {
+	parts := pattern.FindStringSubmatch(value)
+	if len(parts) < 3 {
+		return 0, fmt.Errorf("error parsing value=%s", value)
+	}
+	bytesString := parts[1]
+	multiple := parts[2]
+	bytes, err := strconv.ParseFloat(bytesString, 64)
+	if err != nil {
+		return
+	}
+
+	switch multiple {
+	default:
+		return int64(bytes), nil
+	case "K", "KB":
+		return int64(bytes * KB), nil
+	case "M", "MB":
+		return int64(bytes * MB), nil
+	case "G", "GB":
+		return int64(bytes * GB), nil
+	case "T", "TB":
+		return int64(bytes * TB), nil
+	case "P", "PB":
+		return int64(bytes * PB), nil
+	case "E", "EB":
+		return int64(bytes * EB), nil
+	}
+}
+
+// Format wraps global Bytes's Format function.
+func Format(b int64) string {
+	return global.Format(b)
+}
+
+// Parse wraps global Bytes's Parse function.
+func Parse(val string) (int64, error) {
+	return global.Parse(val)
+}

+ 86 - 0
vendor/github.com/labstack/gommon/color/README.md

@@ -0,0 +1,86 @@
+# Color
+
+Style terminal text.
+
+## Installation
+
+```sh
+go get github.com/labstack/gommon/color
+```
+
+## Windows?
+
+Try [cmder](http://bliker.github.io/cmder) or https://github.com/mattn/go-colorable
+
+## [Usage](https://github.com/labstack/gommon/blob/master/color/color_test.go)
+
+```sh
+import github.com/labstack/gommon/color
+```
+
+### Colored text
+
+```go
+color.Println(color.Black("black"))
+color.Println(color.Red("red"))
+color.Println(color.Green("green"))
+color.Println(color.Yellow("yellow"))
+color.Println(color.Blue("blue"))
+color.Println(color.Magenta("magenta"))
+color.Println(color.Cyan("cyan"))
+color.Println(color.White("white"))
+color.Println(color.Grey("grey"))
+```
+![Colored Text](http://i.imgur.com/8RtY1QR.png)
+
+### Colored background
+
+```go
+color.Println(color.BlackBg("black background", color.Wht))
+color.Println(color.RedBg("red background"))
+color.Println(color.GreenBg("green background"))
+color.Println(color.YellowBg("yellow background"))
+color.Println(color.BlueBg("blue background"))
+color.Println(color.MagentaBg("magenta background"))
+color.Println(color.CyanBg("cyan background"))
+color.Println(color.WhiteBg("white background"))
+```
+![Colored Background](http://i.imgur.com/SrrS6lw.png)
+
+### Emphasis
+
+```go
+color.Println(color.Bold("bold"))
+color.Println(color.Dim("dim"))
+color.Println(color.Italic("italic"))
+color.Println(color.Underline("underline"))
+color.Println(color.Inverse("inverse"))
+color.Println(color.Hidden("hidden"))
+color.Println(color.Strikeout("strikeout"))
+```
+![Emphasis](http://i.imgur.com/3RSJBbc.png)
+
+### Mix and match
+
+```go
+color.Println(color.Green("bold green with white background", color.B, color.WhtBg))
+color.Println(color.Red("underline red", color.U))
+color.Println(color.Yellow("dim yellow", color.D))
+color.Println(color.Cyan("inverse cyan", color.In))
+color.Println(color.Blue("bold underline dim blue", color.B, color.U, color.D))
+```
+![Mix and match](http://i.imgur.com/jWGq9Ca.png)
+
+### Enable/Disable the package
+
+```go
+color.Disable()
+color.Enable()
+```
+
+### New instance
+
+```go
+c := New()
+c.Green("green")
+```

+ 407 - 0
vendor/github.com/labstack/gommon/color/color.go

@@ -0,0 +1,407 @@
+package color
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+	"os"
+
+	"github.com/mattn/go-colorable"
+	"github.com/mattn/go-isatty"
+)
+
+type (
+	inner func(interface{}, []string, *Color) string
+)
+
+// Color styles
+const (
+	// Blk Black text style
+	Blk = "30"
+	// Rd red text style
+	Rd = "31"
+	// Grn green text style
+	Grn = "32"
+	// Yel yellow text style
+	Yel = "33"
+	// Blu blue text style
+	Blu = "34"
+	// Mgn magenta text style
+	Mgn = "35"
+	// Cyn cyan text style
+	Cyn = "36"
+	// Wht white text style
+	Wht = "37"
+	// Gry grey text style
+	Gry = "90"
+
+	// BlkBg black background style
+	BlkBg = "40"
+	// RdBg red background style
+	RdBg = "41"
+	// GrnBg green background style
+	GrnBg = "42"
+	// YelBg yellow background style
+	YelBg = "43"
+	// BluBg blue background style
+	BluBg = "44"
+	// MgnBg magenta background style
+	MgnBg = "45"
+	// CynBg cyan background style
+	CynBg = "46"
+	// WhtBg white background style
+	WhtBg = "47"
+
+	// R reset emphasis style
+	R = "0"
+	// B bold emphasis style
+	B = "1"
+	// D dim emphasis style
+	D = "2"
+	// I italic emphasis style
+	I = "3"
+	// U underline emphasis style
+	U = "4"
+	// In inverse emphasis style
+	In = "7"
+	// H hidden emphasis style
+	H = "8"
+	// S strikeout emphasis style
+	S = "9"
+)
+
+var (
+	black   = outer(Blk)
+	red     = outer(Rd)
+	green   = outer(Grn)
+	yellow  = outer(Yel)
+	blue    = outer(Blu)
+	magenta = outer(Mgn)
+	cyan    = outer(Cyn)
+	white   = outer(Wht)
+	grey    = outer(Gry)
+
+	blackBg   = outer(BlkBg)
+	redBg     = outer(RdBg)
+	greenBg   = outer(GrnBg)
+	yellowBg  = outer(YelBg)
+	blueBg    = outer(BluBg)
+	magentaBg = outer(MgnBg)
+	cyanBg    = outer(CynBg)
+	whiteBg   = outer(WhtBg)
+
+	reset     = outer(R)
+	bold      = outer(B)
+	dim       = outer(D)
+	italic    = outer(I)
+	underline = outer(U)
+	inverse   = outer(In)
+	hidden    = outer(H)
+	strikeout = outer(S)
+
+	global = New()
+)
+
+func outer(n string) inner {
+	return func(msg interface{}, styles []string, c *Color) string {
+		// TODO: Drop fmt to boost performance?
+		if c.disabled {
+			return fmt.Sprintf("%v", msg)
+		}
+
+		b := new(bytes.Buffer)
+		b.WriteString("\x1b[")
+		b.WriteString(n)
+		for _, s := range styles {
+			b.WriteString(";")
+			b.WriteString(s)
+		}
+		b.WriteString("m")
+		return fmt.Sprintf("%s%v\x1b[0m", b.String(), msg)
+	}
+}
+
+type (
+	Color struct {
+		output   io.Writer
+		disabled bool
+	}
+)
+
+// New creates a Color instance.
+func New() (c *Color) {
+	c = new(Color)
+	c.SetOutput(colorable.NewColorableStdout())
+	return
+}
+
+// Output returns the output.
+func (c *Color) Output() io.Writer {
+	return c.output
+}
+
+// SetOutput sets the output.
+func (c *Color) SetOutput(w io.Writer) {
+	c.output = w
+	if w, ok := w.(*os.File); !ok || !isatty.IsTerminal(w.Fd()) {
+		c.disabled = true
+	}
+}
+
+// Disable disables the colors and styles.
+func (c *Color) Disable() {
+	c.disabled = true
+}
+
+// Enable enables the colors and styles.
+func (c *Color) Enable() {
+	c.disabled = false
+}
+
+// Print is analogous to `fmt.Print` with termial detection.
+func (c *Color) Print(args ...interface{}) {
+	fmt.Fprint(c.output, args...)
+}
+
+// Println is analogous to `fmt.Println` with termial detection.
+func (c *Color) Println(args ...interface{}) {
+	fmt.Fprintln(c.output, args...)
+}
+
+// Printf is analogous to `fmt.Printf` with termial detection.
+func (c *Color) Printf(format string, args ...interface{}) {
+	fmt.Fprintf(c.output, format, args...)
+}
+
+func (c *Color) Black(msg interface{}, styles ...string) string {
+	return black(msg, styles, c)
+}
+
+func (c *Color) Red(msg interface{}, styles ...string) string {
+	return red(msg, styles, c)
+}
+
+func (c *Color) Green(msg interface{}, styles ...string) string {
+	return green(msg, styles, c)
+}
+
+func (c *Color) Yellow(msg interface{}, styles ...string) string {
+	return yellow(msg, styles, c)
+}
+
+func (c *Color) Blue(msg interface{}, styles ...string) string {
+	return blue(msg, styles, c)
+}
+
+func (c *Color) Magenta(msg interface{}, styles ...string) string {
+	return magenta(msg, styles, c)
+}
+
+func (c *Color) Cyan(msg interface{}, styles ...string) string {
+	return cyan(msg, styles, c)
+}
+
+func (c *Color) White(msg interface{}, styles ...string) string {
+	return white(msg, styles, c)
+}
+
+func (c *Color) Grey(msg interface{}, styles ...string) string {
+	return grey(msg, styles, c)
+}
+
+func (c *Color) BlackBg(msg interface{}, styles ...string) string {
+	return blackBg(msg, styles, c)
+}
+
+func (c *Color) RedBg(msg interface{}, styles ...string) string {
+	return redBg(msg, styles, c)
+}
+
+func (c *Color) GreenBg(msg interface{}, styles ...string) string {
+	return greenBg(msg, styles, c)
+}
+
+func (c *Color) YellowBg(msg interface{}, styles ...string) string {
+	return yellowBg(msg, styles, c)
+}
+
+func (c *Color) BlueBg(msg interface{}, styles ...string) string {
+	return blueBg(msg, styles, c)
+}
+
+func (c *Color) MagentaBg(msg interface{}, styles ...string) string {
+	return magentaBg(msg, styles, c)
+}
+
+func (c *Color) CyanBg(msg interface{}, styles ...string) string {
+	return cyanBg(msg, styles, c)
+}
+
+func (c *Color) WhiteBg(msg interface{}, styles ...string) string {
+	return whiteBg(msg, styles, c)
+}
+
+func (c *Color) Reset(msg interface{}, styles ...string) string {
+	return reset(msg, styles, c)
+}
+
+func (c *Color) Bold(msg interface{}, styles ...string) string {
+	return bold(msg, styles, c)
+}
+
+func (c *Color) Dim(msg interface{}, styles ...string) string {
+	return dim(msg, styles, c)
+}
+
+func (c *Color) Italic(msg interface{}, styles ...string) string {
+	return italic(msg, styles, c)
+}
+
+func (c *Color) Underline(msg interface{}, styles ...string) string {
+	return underline(msg, styles, c)
+}
+
+func (c *Color) Inverse(msg interface{}, styles ...string) string {
+	return inverse(msg, styles, c)
+}
+
+func (c *Color) Hidden(msg interface{}, styles ...string) string {
+	return hidden(msg, styles, c)
+}
+
+func (c *Color) Strikeout(msg interface{}, styles ...string) string {
+	return strikeout(msg, styles, c)
+}
+
+// Output returns the output.
+func Output() io.Writer {
+	return global.output
+}
+
+// SetOutput sets the output.
+func SetOutput(w io.Writer) {
+	global.SetOutput(w)
+}
+
+func Disable() {
+	global.Disable()
+}
+
+func Enable() {
+	global.Enable()
+}
+
+// Print is analogous to `fmt.Print` with termial detection.
+func Print(args ...interface{}) {
+	global.Print(args...)
+}
+
+// Println is analogous to `fmt.Println` with termial detection.
+func Println(args ...interface{}) {
+	global.Println(args...)
+}
+
+// Printf is analogous to `fmt.Printf` with termial detection.
+func Printf(format string, args ...interface{}) {
+	global.Printf(format, args...)
+}
+
+func Black(msg interface{}, styles ...string) string {
+	return global.Black(msg, styles...)
+}
+
+func Red(msg interface{}, styles ...string) string {
+	return global.Red(msg, styles...)
+}
+
+func Green(msg interface{}, styles ...string) string {
+	return global.Green(msg, styles...)
+}
+
+func Yellow(msg interface{}, styles ...string) string {
+	return global.Yellow(msg, styles...)
+}
+
+func Blue(msg interface{}, styles ...string) string {
+	return global.Blue(msg, styles...)
+}
+
+func Magenta(msg interface{}, styles ...string) string {
+	return global.Magenta(msg, styles...)
+}
+
+func Cyan(msg interface{}, styles ...string) string {
+	return global.Cyan(msg, styles...)
+}
+
+func White(msg interface{}, styles ...string) string {
+	return global.White(msg, styles...)
+}
+
+func Grey(msg interface{}, styles ...string) string {
+	return global.Grey(msg, styles...)
+}
+
+func BlackBg(msg interface{}, styles ...string) string {
+	return global.BlackBg(msg, styles...)
+}
+
+func RedBg(msg interface{}, styles ...string) string {
+	return global.RedBg(msg, styles...)
+}
+
+func GreenBg(msg interface{}, styles ...string) string {
+	return global.GreenBg(msg, styles...)
+}
+
+func YellowBg(msg interface{}, styles ...string) string {
+	return global.YellowBg(msg, styles...)
+}
+
+func BlueBg(msg interface{}, styles ...string) string {
+	return global.BlueBg(msg, styles...)
+}
+
+func MagentaBg(msg interface{}, styles ...string) string {
+	return global.MagentaBg(msg, styles...)
+}
+
+func CyanBg(msg interface{}, styles ...string) string {
+	return global.CyanBg(msg, styles...)
+}
+
+func WhiteBg(msg interface{}, styles ...string) string {
+	return global.WhiteBg(msg, styles...)
+}
+
+func Reset(msg interface{}, styles ...string) string {
+	return global.Reset(msg, styles...)
+}
+
+func Bold(msg interface{}, styles ...string) string {
+	return global.Bold(msg, styles...)
+}
+
+func Dim(msg interface{}, styles ...string) string {
+	return global.Dim(msg, styles...)
+}
+
+func Italic(msg interface{}, styles ...string) string {
+	return global.Italic(msg, styles...)
+}
+
+func Underline(msg interface{}, styles ...string) string {
+	return global.Underline(msg, styles...)
+}
+
+func Inverse(msg interface{}, styles ...string) string {
+	return global.Inverse(msg, styles...)
+}
+
+func Hidden(msg interface{}, styles ...string) string {
+	return global.Hidden(msg, styles...)
+}
+
+func Strikeout(msg interface{}, styles ...string) string {
+	return global.Strikeout(msg, styles...)
+}

+ 5 - 0
vendor/github.com/labstack/gommon/log/README.md

@@ -0,0 +1,5 @@
+## WORK IN PROGRESS
+
+### Usage
+
+[log_test.go](log_test.go)

+ 13 - 0
vendor/github.com/labstack/gommon/log/color.go

@@ -0,0 +1,13 @@
+// +build !appengine
+
+package log
+
+import (
+	"io"
+
+	"github.com/mattn/go-colorable"
+)
+
+func output() io.Writer {
+	return colorable.NewColorableStdout()
+}

+ 415 - 0
vendor/github.com/labstack/gommon/log/log.go

@@ -0,0 +1,415 @@
+package log
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"io"
+	"os"
+	"path"
+	"runtime"
+	"strconv"
+	"sync"
+	"time"
+
+	"github.com/mattn/go-isatty"
+	"github.com/valyala/fasttemplate"
+
+	"github.com/labstack/gommon/color"
+)
+
+type (
+	Logger struct {
+		prefix     string
+		level      Lvl
+		skip       int
+		output     io.Writer
+		template   *fasttemplate.Template
+		levels     []string
+		color      *color.Color
+		bufferPool sync.Pool
+		mutex      sync.Mutex
+	}
+
+	Lvl uint8
+
+	JSON map[string]interface{}
+)
+
+const (
+	DEBUG Lvl = iota + 1
+	INFO
+	WARN
+	ERROR
+	OFF
+	panicLevel
+	fatalLevel
+)
+
+var (
+	global        = New("-")
+	defaultHeader = `{"time":"${time_rfc3339_nano}","level":"${level}","prefix":"${prefix}",` +
+		`"file":"${short_file}","line":"${line}"}`
+)
+
+func init() {
+	global.skip = 3
+}
+
+func New(prefix string) (l *Logger) {
+	l = &Logger{
+		level:    INFO,
+		skip:     2,
+		prefix:   prefix,
+		template: l.newTemplate(defaultHeader),
+		color:    color.New(),
+		bufferPool: sync.Pool{
+			New: func() interface{} {
+				return bytes.NewBuffer(make([]byte, 256))
+			},
+		},
+	}
+	l.initLevels()
+	l.SetOutput(output())
+	return
+}
+
+func (l *Logger) initLevels() {
+	l.levels = []string{
+		"-",
+		l.color.Blue("DEBUG"),
+		l.color.Green("INFO"),
+		l.color.Yellow("WARN"),
+		l.color.Red("ERROR"),
+		"",
+		l.color.Yellow("PANIC", color.U),
+		l.color.Red("FATAL", color.U),
+	}
+}
+
+func (l *Logger) newTemplate(format string) *fasttemplate.Template {
+	return fasttemplate.New(format, "${", "}")
+}
+
+func (l *Logger) DisableColor() {
+	l.color.Disable()
+	l.initLevels()
+}
+
+func (l *Logger) EnableColor() {
+	l.color.Enable()
+	l.initLevels()
+}
+
+func (l *Logger) Prefix() string {
+	return l.prefix
+}
+
+func (l *Logger) SetPrefix(p string) {
+	l.prefix = p
+}
+
+func (l *Logger) Level() Lvl {
+	return l.level
+}
+
+func (l *Logger) SetLevel(v Lvl) {
+	l.level = v
+}
+
+func (l *Logger) Output() io.Writer {
+	return l.output
+}
+
+func (l *Logger) SetOutput(w io.Writer) {
+	l.output = w
+	if w, ok := w.(*os.File); !ok || !isatty.IsTerminal(w.Fd()) {
+		l.DisableColor()
+	}
+}
+
+func (l *Logger) Color() *color.Color {
+	return l.color
+}
+
+func (l *Logger) SetHeader(h string) {
+	l.template = l.newTemplate(h)
+}
+
+func (l *Logger) Print(i ...interface{}) {
+	l.log(0, "", i...)
+	// fmt.Fprintln(l.output, i...)
+}
+
+func (l *Logger) Printf(format string, args ...interface{}) {
+	l.log(0, format, args...)
+}
+
+func (l *Logger) Printj(j JSON) {
+	l.log(0, "json", j)
+}
+
+func (l *Logger) Debug(i ...interface{}) {
+	l.log(DEBUG, "", i...)
+}
+
+func (l *Logger) Debugf(format string, args ...interface{}) {
+	l.log(DEBUG, format, args...)
+}
+
+func (l *Logger) Debugj(j JSON) {
+	l.log(DEBUG, "json", j)
+}
+
+func (l *Logger) Info(i ...interface{}) {
+	l.log(INFO, "", i...)
+}
+
+func (l *Logger) Infof(format string, args ...interface{}) {
+	l.log(INFO, format, args...)
+}
+
+func (l *Logger) Infoj(j JSON) {
+	l.log(INFO, "json", j)
+}
+
+func (l *Logger) Warn(i ...interface{}) {
+	l.log(WARN, "", i...)
+}
+
+func (l *Logger) Warnf(format string, args ...interface{}) {
+	l.log(WARN, format, args...)
+}
+
+func (l *Logger) Warnj(j JSON) {
+	l.log(WARN, "json", j)
+}
+
+func (l *Logger) Error(i ...interface{}) {
+	l.log(ERROR, "", i...)
+}
+
+func (l *Logger) Errorf(format string, args ...interface{}) {
+	l.log(ERROR, format, args...)
+}
+
+func (l *Logger) Errorj(j JSON) {
+	l.log(ERROR, "json", j)
+}
+
+func (l *Logger) Fatal(i ...interface{}) {
+	l.log(fatalLevel, "", i...)
+	os.Exit(1)
+}
+
+func (l *Logger) Fatalf(format string, args ...interface{}) {
+	l.log(fatalLevel, format, args...)
+	os.Exit(1)
+}
+
+func (l *Logger) Fatalj(j JSON) {
+	l.log(fatalLevel, "json", j)
+	os.Exit(1)
+}
+
+func (l *Logger) Panic(i ...interface{}) {
+	l.log(panicLevel, "", i...)
+	panic(fmt.Sprint(i...))
+}
+
+func (l *Logger) Panicf(format string, args ...interface{}) {
+	l.log(panicLevel, format, args...)
+	panic(fmt.Sprintf(format, args))
+}
+
+func (l *Logger) Panicj(j JSON) {
+	l.log(panicLevel, "json", j)
+	panic(j)
+}
+
+func DisableColor() {
+	global.DisableColor()
+}
+
+func EnableColor() {
+	global.EnableColor()
+}
+
+func Prefix() string {
+	return global.Prefix()
+}
+
+func SetPrefix(p string) {
+	global.SetPrefix(p)
+}
+
+func Level() Lvl {
+	return global.Level()
+}
+
+func SetLevel(v Lvl) {
+	global.SetLevel(v)
+}
+
+func Output() io.Writer {
+	return global.Output()
+}
+
+func SetOutput(w io.Writer) {
+	global.SetOutput(w)
+}
+
+func SetHeader(h string) {
+	global.SetHeader(h)
+}
+
+func Print(i ...interface{}) {
+	global.Print(i...)
+}
+
+func Printf(format string, args ...interface{}) {
+	global.Printf(format, args...)
+}
+
+func Printj(j JSON) {
+	global.Printj(j)
+}
+
+func Debug(i ...interface{}) {
+	global.Debug(i...)
+}
+
+func Debugf(format string, args ...interface{}) {
+	global.Debugf(format, args...)
+}
+
+func Debugj(j JSON) {
+	global.Debugj(j)
+}
+
+func Info(i ...interface{}) {
+	global.Info(i...)
+}
+
+func Infof(format string, args ...interface{}) {
+	global.Infof(format, args...)
+}
+
+func Infoj(j JSON) {
+	global.Infoj(j)
+}
+
+func Warn(i ...interface{}) {
+	global.Warn(i...)
+}
+
+func Warnf(format string, args ...interface{}) {
+	global.Warnf(format, args...)
+}
+
+func Warnj(j JSON) {
+	global.Warnj(j)
+}
+
+func Error(i ...interface{}) {
+	global.Error(i...)
+}
+
+func Errorf(format string, args ...interface{}) {
+	global.Errorf(format, args...)
+}
+
+func Errorj(j JSON) {
+	global.Errorj(j)
+}
+
+func Fatal(i ...interface{}) {
+	global.Fatal(i...)
+}
+
+func Fatalf(format string, args ...interface{}) {
+	global.Fatalf(format, args...)
+}
+
+func Fatalj(j JSON) {
+	global.Fatalj(j)
+}
+
+func Panic(i ...interface{}) {
+	global.Panic(i...)
+}
+
+func Panicf(format string, args ...interface{}) {
+	global.Panicf(format, args...)
+}
+
+func Panicj(j JSON) {
+	global.Panicj(j)
+}
+
+func (l *Logger) log(v Lvl, format string, args ...interface{}) {
+	l.mutex.Lock()
+	defer l.mutex.Unlock()
+	buf := l.bufferPool.Get().(*bytes.Buffer)
+	buf.Reset()
+	defer l.bufferPool.Put(buf)
+	_, file, line, _ := runtime.Caller(l.skip)
+
+	if v >= l.level || v == 0 {
+		message := ""
+		if format == "" {
+			message = fmt.Sprint(args...)
+		} else if format == "json" {
+			b, err := json.Marshal(args[0])
+			if err != nil {
+				panic(err)
+			}
+			message = string(b)
+		} else {
+			message = fmt.Sprintf(format, args...)
+		}
+
+		_, err := l.template.ExecuteFunc(buf, func(w io.Writer, tag string) (int, error) {
+			switch tag {
+			case "time_rfc3339":
+				return w.Write([]byte(time.Now().Format(time.RFC3339)))
+			case "time_rfc3339_nano":
+				return w.Write([]byte(time.Now().Format(time.RFC3339Nano)))
+			case "level":
+				return w.Write([]byte(l.levels[v]))
+			case "prefix":
+				return w.Write([]byte(l.prefix))
+			case "long_file":
+				return w.Write([]byte(file))
+			case "short_file":
+				return w.Write([]byte(path.Base(file)))
+			case "line":
+				return w.Write([]byte(strconv.Itoa(line)))
+			}
+			return 0, nil
+		})
+
+		if err == nil {
+			s := buf.String()
+			i := buf.Len() - 1
+			if s[i] == '}' {
+				// JSON header
+				buf.Truncate(i)
+				buf.WriteByte(',')
+				if format == "json" {
+					buf.WriteString(message[1:])
+				} else {
+					buf.WriteString(`"message":`)
+					buf.WriteString(strconv.Quote(message))
+					buf.WriteString(`}`)
+				}
+			} else {
+				// Text header
+				buf.WriteByte(' ')
+				buf.WriteString(message)
+			}
+			buf.WriteByte('\n')
+			l.output.Write(buf.Bytes())
+		}
+	}
+}

+ 12 - 0
vendor/github.com/labstack/gommon/log/white.go

@@ -0,0 +1,12 @@
+// +build appengine
+
+package log
+
+import (
+	"io"
+	"os"
+)
+
+func output() io.Writer {
+	return os.Stdout
+}

+ 48 - 0
vendor/github.com/labstack/gommon/random/random.go

@@ -0,0 +1,48 @@
+package random
+
+import (
+	"math/rand"
+	"strings"
+	"time"
+)
+
+type (
+	Random struct {
+	}
+)
+
+// Charsets
+const (
+	Uppercase    = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+	Lowercase    = "abcdefghijklmnopqrstuvwxyz"
+	Alphabetic   = Uppercase + Lowercase
+	Numeric      = "0123456789"
+	Alphanumeric = Alphabetic + Numeric
+	Symbols      = "`" + `~!@#$%^&*()-_+={}[]|\;:"<>,./?`
+	Hex          = Numeric + "abcdef"
+)
+
+var (
+	global = New()
+)
+
+func New() *Random {
+	rand.Seed(time.Now().UnixNano())
+	return new(Random)
+}
+
+func (r *Random) String(length uint8, charsets ...string) string {
+	charset := strings.Join(charsets, "")
+	if charset == "" {
+		charset = Alphanumeric
+	}
+	b := make([]byte, length)
+	for i := range b {
+		b[i] = charset[rand.Int63()%int64(len(charset))]
+	}
+	return string(b)
+}
+
+func String(length uint8, charsets ...string) string {
+	return global.String(length, charsets...)
+}

+ 9 - 0
vendor/github.com/mattn/go-colorable/.travis.yml

@@ -0,0 +1,9 @@
+language: go
+go:
+  - tip
+
+before_install:
+  - go get github.com/mattn/goveralls
+  - go get golang.org/x/tools/cmd/cover
+script:
+  - $HOME/gopath/bin/goveralls -repotoken xnXqRGwgW3SXIguzxf90ZSK1GPYZPaGrw

+ 21 - 0
vendor/github.com/mattn/go-colorable/LICENSE

@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 Yasuhiro Matsumoto
+
+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.

+ 48 - 0
vendor/github.com/mattn/go-colorable/README.md

@@ -0,0 +1,48 @@
+# go-colorable
+
+[![Godoc Reference](https://godoc.org/github.com/mattn/go-colorable?status.svg)](http://godoc.org/github.com/mattn/go-colorable)
+[![Build Status](https://travis-ci.org/mattn/go-colorable.svg?branch=master)](https://travis-ci.org/mattn/go-colorable)
+[![Coverage Status](https://coveralls.io/repos/github/mattn/go-colorable/badge.svg?branch=master)](https://coveralls.io/github/mattn/go-colorable?branch=master)
+[![Go Report Card](https://goreportcard.com/badge/mattn/go-colorable)](https://goreportcard.com/report/mattn/go-colorable)
+
+Colorable writer for windows.
+
+For example, most of logger packages doesn't show colors on windows. (I know we can do it with ansicon. But I don't want.)
+This package is possible to handle escape sequence for ansi color on windows.
+
+## Too Bad!
+
+![](https://raw.githubusercontent.com/mattn/go-colorable/gh-pages/bad.png)
+
+
+## So Good!
+
+![](https://raw.githubusercontent.com/mattn/go-colorable/gh-pages/good.png)
+
+## Usage
+
+```go
+logrus.SetFormatter(&logrus.TextFormatter{ForceColors: true})
+logrus.SetOutput(colorable.NewColorableStdout())
+
+logrus.Info("succeeded")
+logrus.Warn("not correct")
+logrus.Error("something error")
+logrus.Fatal("panic")
+```
+
+You can compile above code on non-windows OSs.
+
+## Installation
+
+```
+$ go get github.com/mattn/go-colorable
+```
+
+# License
+
+MIT
+
+# Author
+
+Yasuhiro Matsumoto (a.k.a mattn)

+ 29 - 0
vendor/github.com/mattn/go-colorable/colorable_appengine.go

@@ -0,0 +1,29 @@
+// +build appengine
+
+package colorable
+
+import (
+	"io"
+	"os"
+
+	_ "github.com/mattn/go-isatty"
+)
+
+// NewColorable return new instance of Writer which handle escape sequence.
+func NewColorable(file *os.File) io.Writer {
+	if file == nil {
+		panic("nil passed instead of *os.File to NewColorable()")
+	}
+
+	return file
+}
+
+// NewColorableStdout return new instance of Writer which handle escape sequence for stdout.
+func NewColorableStdout() io.Writer {
+	return os.Stdout
+}
+
+// NewColorableStderr return new instance of Writer which handle escape sequence for stderr.
+func NewColorableStderr() io.Writer {
+	return os.Stderr
+}

+ 30 - 0
vendor/github.com/mattn/go-colorable/colorable_others.go

@@ -0,0 +1,30 @@
+// +build !windows
+// +build !appengine
+
+package colorable
+
+import (
+	"io"
+	"os"
+
+	_ "github.com/mattn/go-isatty"
+)
+
+// NewColorable return new instance of Writer which handle escape sequence.
+func NewColorable(file *os.File) io.Writer {
+	if file == nil {
+		panic("nil passed instead of *os.File to NewColorable()")
+	}
+
+	return file
+}
+
+// NewColorableStdout return new instance of Writer which handle escape sequence for stdout.
+func NewColorableStdout() io.Writer {
+	return os.Stdout
+}
+
+// NewColorableStderr return new instance of Writer which handle escape sequence for stderr.
+func NewColorableStderr() io.Writer {
+	return os.Stderr
+}

+ 884 - 0
vendor/github.com/mattn/go-colorable/colorable_windows.go

@@ -0,0 +1,884 @@
+// +build windows
+// +build !appengine
+
+package colorable
+
+import (
+	"bytes"
+	"io"
+	"math"
+	"os"
+	"strconv"
+	"strings"
+	"syscall"
+	"unsafe"
+
+	"github.com/mattn/go-isatty"
+)
+
+const (
+	foregroundBlue      = 0x1
+	foregroundGreen     = 0x2
+	foregroundRed       = 0x4
+	foregroundIntensity = 0x8
+	foregroundMask      = (foregroundRed | foregroundBlue | foregroundGreen | foregroundIntensity)
+	backgroundBlue      = 0x10
+	backgroundGreen     = 0x20
+	backgroundRed       = 0x40
+	backgroundIntensity = 0x80
+	backgroundMask      = (backgroundRed | backgroundBlue | backgroundGreen | backgroundIntensity)
+)
+
+type wchar uint16
+type short int16
+type dword uint32
+type word uint16
+
+type coord struct {
+	x short
+	y short
+}
+
+type smallRect struct {
+	left   short
+	top    short
+	right  short
+	bottom short
+}
+
+type consoleScreenBufferInfo struct {
+	size              coord
+	cursorPosition    coord
+	attributes        word
+	window            smallRect
+	maximumWindowSize coord
+}
+
+type consoleCursorInfo struct {
+	size    dword
+	visible int32
+}
+
+var (
+	kernel32                       = syscall.NewLazyDLL("kernel32.dll")
+	procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
+	procSetConsoleTextAttribute    = kernel32.NewProc("SetConsoleTextAttribute")
+	procSetConsoleCursorPosition   = kernel32.NewProc("SetConsoleCursorPosition")
+	procFillConsoleOutputCharacter = kernel32.NewProc("FillConsoleOutputCharacterW")
+	procFillConsoleOutputAttribute = kernel32.NewProc("FillConsoleOutputAttribute")
+	procGetConsoleCursorInfo       = kernel32.NewProc("GetConsoleCursorInfo")
+	procSetConsoleCursorInfo       = kernel32.NewProc("SetConsoleCursorInfo")
+	procSetConsoleTitle            = kernel32.NewProc("SetConsoleTitleW")
+)
+
+// Writer provide colorable Writer to the console
+type Writer struct {
+	out     io.Writer
+	handle  syscall.Handle
+	oldattr word
+	oldpos  coord
+}
+
+// NewColorable return new instance of Writer which handle escape sequence from File.
+func NewColorable(file *os.File) io.Writer {
+	if file == nil {
+		panic("nil passed instead of *os.File to NewColorable()")
+	}
+
+	if isatty.IsTerminal(file.Fd()) {
+		var csbi consoleScreenBufferInfo
+		handle := syscall.Handle(file.Fd())
+		procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
+		return &Writer{out: file, handle: handle, oldattr: csbi.attributes, oldpos: coord{0, 0}}
+	}
+	return file
+}
+
+// NewColorableStdout return new instance of Writer which handle escape sequence for stdout.
+func NewColorableStdout() io.Writer {
+	return NewColorable(os.Stdout)
+}
+
+// NewColorableStderr return new instance of Writer which handle escape sequence for stderr.
+func NewColorableStderr() io.Writer {
+	return NewColorable(os.Stderr)
+}
+
+var color256 = map[int]int{
+	0:   0x000000,
+	1:   0x800000,
+	2:   0x008000,
+	3:   0x808000,
+	4:   0x000080,
+	5:   0x800080,
+	6:   0x008080,
+	7:   0xc0c0c0,
+	8:   0x808080,
+	9:   0xff0000,
+	10:  0x00ff00,
+	11:  0xffff00,
+	12:  0x0000ff,
+	13:  0xff00ff,
+	14:  0x00ffff,
+	15:  0xffffff,
+	16:  0x000000,
+	17:  0x00005f,
+	18:  0x000087,
+	19:  0x0000af,
+	20:  0x0000d7,
+	21:  0x0000ff,
+	22:  0x005f00,
+	23:  0x005f5f,
+	24:  0x005f87,
+	25:  0x005faf,
+	26:  0x005fd7,
+	27:  0x005fff,
+	28:  0x008700,
+	29:  0x00875f,
+	30:  0x008787,
+	31:  0x0087af,
+	32:  0x0087d7,
+	33:  0x0087ff,
+	34:  0x00af00,
+	35:  0x00af5f,
+	36:  0x00af87,
+	37:  0x00afaf,
+	38:  0x00afd7,
+	39:  0x00afff,
+	40:  0x00d700,
+	41:  0x00d75f,
+	42:  0x00d787,
+	43:  0x00d7af,
+	44:  0x00d7d7,
+	45:  0x00d7ff,
+	46:  0x00ff00,
+	47:  0x00ff5f,
+	48:  0x00ff87,
+	49:  0x00ffaf,
+	50:  0x00ffd7,
+	51:  0x00ffff,
+	52:  0x5f0000,
+	53:  0x5f005f,
+	54:  0x5f0087,
+	55:  0x5f00af,
+	56:  0x5f00d7,
+	57:  0x5f00ff,
+	58:  0x5f5f00,
+	59:  0x5f5f5f,
+	60:  0x5f5f87,
+	61:  0x5f5faf,
+	62:  0x5f5fd7,
+	63:  0x5f5fff,
+	64:  0x5f8700,
+	65:  0x5f875f,
+	66:  0x5f8787,
+	67:  0x5f87af,
+	68:  0x5f87d7,
+	69:  0x5f87ff,
+	70:  0x5faf00,
+	71:  0x5faf5f,
+	72:  0x5faf87,
+	73:  0x5fafaf,
+	74:  0x5fafd7,
+	75:  0x5fafff,
+	76:  0x5fd700,
+	77:  0x5fd75f,
+	78:  0x5fd787,
+	79:  0x5fd7af,
+	80:  0x5fd7d7,
+	81:  0x5fd7ff,
+	82:  0x5fff00,
+	83:  0x5fff5f,
+	84:  0x5fff87,
+	85:  0x5fffaf,
+	86:  0x5fffd7,
+	87:  0x5fffff,
+	88:  0x870000,
+	89:  0x87005f,
+	90:  0x870087,
+	91:  0x8700af,
+	92:  0x8700d7,
+	93:  0x8700ff,
+	94:  0x875f00,
+	95:  0x875f5f,
+	96:  0x875f87,
+	97:  0x875faf,
+	98:  0x875fd7,
+	99:  0x875fff,
+	100: 0x878700,
+	101: 0x87875f,
+	102: 0x878787,
+	103: 0x8787af,
+	104: 0x8787d7,
+	105: 0x8787ff,
+	106: 0x87af00,
+	107: 0x87af5f,
+	108: 0x87af87,
+	109: 0x87afaf,
+	110: 0x87afd7,
+	111: 0x87afff,
+	112: 0x87d700,
+	113: 0x87d75f,
+	114: 0x87d787,
+	115: 0x87d7af,
+	116: 0x87d7d7,
+	117: 0x87d7ff,
+	118: 0x87ff00,
+	119: 0x87ff5f,
+	120: 0x87ff87,
+	121: 0x87ffaf,
+	122: 0x87ffd7,
+	123: 0x87ffff,
+	124: 0xaf0000,
+	125: 0xaf005f,
+	126: 0xaf0087,
+	127: 0xaf00af,
+	128: 0xaf00d7,
+	129: 0xaf00ff,
+	130: 0xaf5f00,
+	131: 0xaf5f5f,
+	132: 0xaf5f87,
+	133: 0xaf5faf,
+	134: 0xaf5fd7,
+	135: 0xaf5fff,
+	136: 0xaf8700,
+	137: 0xaf875f,
+	138: 0xaf8787,
+	139: 0xaf87af,
+	140: 0xaf87d7,
+	141: 0xaf87ff,
+	142: 0xafaf00,
+	143: 0xafaf5f,
+	144: 0xafaf87,
+	145: 0xafafaf,
+	146: 0xafafd7,
+	147: 0xafafff,
+	148: 0xafd700,
+	149: 0xafd75f,
+	150: 0xafd787,
+	151: 0xafd7af,
+	152: 0xafd7d7,
+	153: 0xafd7ff,
+	154: 0xafff00,
+	155: 0xafff5f,
+	156: 0xafff87,
+	157: 0xafffaf,
+	158: 0xafffd7,
+	159: 0xafffff,
+	160: 0xd70000,
+	161: 0xd7005f,
+	162: 0xd70087,
+	163: 0xd700af,
+	164: 0xd700d7,
+	165: 0xd700ff,
+	166: 0xd75f00,
+	167: 0xd75f5f,
+	168: 0xd75f87,
+	169: 0xd75faf,
+	170: 0xd75fd7,
+	171: 0xd75fff,
+	172: 0xd78700,
+	173: 0xd7875f,
+	174: 0xd78787,
+	175: 0xd787af,
+	176: 0xd787d7,
+	177: 0xd787ff,
+	178: 0xd7af00,
+	179: 0xd7af5f,
+	180: 0xd7af87,
+	181: 0xd7afaf,
+	182: 0xd7afd7,
+	183: 0xd7afff,
+	184: 0xd7d700,
+	185: 0xd7d75f,
+	186: 0xd7d787,
+	187: 0xd7d7af,
+	188: 0xd7d7d7,
+	189: 0xd7d7ff,
+	190: 0xd7ff00,
+	191: 0xd7ff5f,
+	192: 0xd7ff87,
+	193: 0xd7ffaf,
+	194: 0xd7ffd7,
+	195: 0xd7ffff,
+	196: 0xff0000,
+	197: 0xff005f,
+	198: 0xff0087,
+	199: 0xff00af,
+	200: 0xff00d7,
+	201: 0xff00ff,
+	202: 0xff5f00,
+	203: 0xff5f5f,
+	204: 0xff5f87,
+	205: 0xff5faf,
+	206: 0xff5fd7,
+	207: 0xff5fff,
+	208: 0xff8700,
+	209: 0xff875f,
+	210: 0xff8787,
+	211: 0xff87af,
+	212: 0xff87d7,
+	213: 0xff87ff,
+	214: 0xffaf00,
+	215: 0xffaf5f,
+	216: 0xffaf87,
+	217: 0xffafaf,
+	218: 0xffafd7,
+	219: 0xffafff,
+	220: 0xffd700,
+	221: 0xffd75f,
+	222: 0xffd787,
+	223: 0xffd7af,
+	224: 0xffd7d7,
+	225: 0xffd7ff,
+	226: 0xffff00,
+	227: 0xffff5f,
+	228: 0xffff87,
+	229: 0xffffaf,
+	230: 0xffffd7,
+	231: 0xffffff,
+	232: 0x080808,
+	233: 0x121212,
+	234: 0x1c1c1c,
+	235: 0x262626,
+	236: 0x303030,
+	237: 0x3a3a3a,
+	238: 0x444444,
+	239: 0x4e4e4e,
+	240: 0x585858,
+	241: 0x626262,
+	242: 0x6c6c6c,
+	243: 0x767676,
+	244: 0x808080,
+	245: 0x8a8a8a,
+	246: 0x949494,
+	247: 0x9e9e9e,
+	248: 0xa8a8a8,
+	249: 0xb2b2b2,
+	250: 0xbcbcbc,
+	251: 0xc6c6c6,
+	252: 0xd0d0d0,
+	253: 0xdadada,
+	254: 0xe4e4e4,
+	255: 0xeeeeee,
+}
+
+// `\033]0;TITLESTR\007`
+func doTitleSequence(er *bytes.Reader) error {
+	var c byte
+	var err error
+
+	c, err = er.ReadByte()
+	if err != nil {
+		return err
+	}
+	if c != '0' && c != '2' {
+		return nil
+	}
+	c, err = er.ReadByte()
+	if err != nil {
+		return err
+	}
+	if c != ';' {
+		return nil
+	}
+	title := make([]byte, 0, 80)
+	for {
+		c, err = er.ReadByte()
+		if err != nil {
+			return err
+		}
+		if c == 0x07 || c == '\n' {
+			break
+		}
+		title = append(title, c)
+	}
+	if len(title) > 0 {
+		title8, err := syscall.UTF16PtrFromString(string(title))
+		if err == nil {
+			procSetConsoleTitle.Call(uintptr(unsafe.Pointer(title8)))
+		}
+	}
+	return nil
+}
+
+// Write write data on console
+func (w *Writer) Write(data []byte) (n int, err error) {
+	var csbi consoleScreenBufferInfo
+	procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
+
+	er := bytes.NewReader(data)
+	var bw [1]byte
+loop:
+	for {
+		c1, err := er.ReadByte()
+		if err != nil {
+			break loop
+		}
+		if c1 != 0x1b {
+			bw[0] = c1
+			w.out.Write(bw[:])
+			continue
+		}
+		c2, err := er.ReadByte()
+		if err != nil {
+			break loop
+		}
+
+		if c2 == ']' {
+			if err := doTitleSequence(er); err != nil {
+				break loop
+			}
+			continue
+		}
+		if c2 != 0x5b {
+			continue
+		}
+
+		var buf bytes.Buffer
+		var m byte
+		for {
+			c, err := er.ReadByte()
+			if err != nil {
+				break loop
+			}
+			if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' {
+				m = c
+				break
+			}
+			buf.Write([]byte(string(c)))
+		}
+
+		switch m {
+		case 'A':
+			n, err = strconv.Atoi(buf.String())
+			if err != nil {
+				continue
+			}
+			procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
+			csbi.cursorPosition.y -= short(n)
+			procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
+		case 'B':
+			n, err = strconv.Atoi(buf.String())
+			if err != nil {
+				continue
+			}
+			procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
+			csbi.cursorPosition.y += short(n)
+			procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
+		case 'C':
+			n, err = strconv.Atoi(buf.String())
+			if err != nil {
+				continue
+			}
+			procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
+			csbi.cursorPosition.x += short(n)
+			procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
+		case 'D':
+			n, err = strconv.Atoi(buf.String())
+			if err != nil {
+				continue
+			}
+			procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
+			csbi.cursorPosition.x -= short(n)
+			procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
+		case 'E':
+			n, err = strconv.Atoi(buf.String())
+			if err != nil {
+				continue
+			}
+			procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
+			csbi.cursorPosition.x = 0
+			csbi.cursorPosition.y += short(n)
+			procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
+		case 'F':
+			n, err = strconv.Atoi(buf.String())
+			if err != nil {
+				continue
+			}
+			procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
+			csbi.cursorPosition.x = 0
+			csbi.cursorPosition.y -= short(n)
+			procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
+		case 'G':
+			n, err = strconv.Atoi(buf.String())
+			if err != nil {
+				continue
+			}
+			procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
+			csbi.cursorPosition.x = short(n - 1)
+			procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
+		case 'H', 'f':
+			procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
+			if buf.Len() > 0 {
+				token := strings.Split(buf.String(), ";")
+				switch len(token) {
+				case 1:
+					n1, err := strconv.Atoi(token[0])
+					if err != nil {
+						continue
+					}
+					csbi.cursorPosition.y = short(n1 - 1)
+				case 2:
+					n1, err := strconv.Atoi(token[0])
+					if err != nil {
+						continue
+					}
+					n2, err := strconv.Atoi(token[1])
+					if err != nil {
+						continue
+					}
+					csbi.cursorPosition.x = short(n2 - 1)
+					csbi.cursorPosition.y = short(n1 - 1)
+				}
+			} else {
+				csbi.cursorPosition.y = 0
+			}
+			procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
+		case 'J':
+			n := 0
+			if buf.Len() > 0 {
+				n, err = strconv.Atoi(buf.String())
+				if err != nil {
+					continue
+				}
+			}
+			var count, written dword
+			var cursor coord
+			procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
+			switch n {
+			case 0:
+				cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y}
+				count = dword(csbi.size.x - csbi.cursorPosition.x + (csbi.size.y-csbi.cursorPosition.y)*csbi.size.x)
+			case 1:
+				cursor = coord{x: csbi.window.left, y: csbi.window.top}
+				count = dword(csbi.size.x - csbi.cursorPosition.x + (csbi.window.top-csbi.cursorPosition.y)*csbi.size.x)
+			case 2:
+				cursor = coord{x: csbi.window.left, y: csbi.window.top}
+				count = dword(csbi.size.x - csbi.cursorPosition.x + (csbi.size.y-csbi.cursorPosition.y)*csbi.size.x)
+			}
+			procFillConsoleOutputCharacter.Call(uintptr(w.handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
+			procFillConsoleOutputAttribute.Call(uintptr(w.handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
+		case 'K':
+			n := 0
+			if buf.Len() > 0 {
+				n, err = strconv.Atoi(buf.String())
+				if err != nil {
+					continue
+				}
+			}
+			procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
+			var cursor coord
+			var count, written dword
+			switch n {
+			case 0:
+				cursor = coord{x: csbi.cursorPosition.x + 1, y: csbi.cursorPosition.y}
+				count = dword(csbi.size.x - csbi.cursorPosition.x - 1)
+			case 1:
+				cursor = coord{x: csbi.window.left, y: csbi.window.top + csbi.cursorPosition.y}
+				count = dword(csbi.size.x - csbi.cursorPosition.x)
+			case 2:
+				cursor = coord{x: csbi.window.left, y: csbi.window.top + csbi.cursorPosition.y}
+				count = dword(csbi.size.x)
+			}
+			procFillConsoleOutputCharacter.Call(uintptr(w.handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
+			procFillConsoleOutputAttribute.Call(uintptr(w.handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
+		case 'm':
+			procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
+			attr := csbi.attributes
+			cs := buf.String()
+			if cs == "" {
+				procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(w.oldattr))
+				continue
+			}
+			token := strings.Split(cs, ";")
+			for i := 0; i < len(token); i++ {
+				ns := token[i]
+				if n, err = strconv.Atoi(ns); err == nil {
+					switch {
+					case n == 0 || n == 100:
+						attr = w.oldattr
+					case 1 <= n && n <= 5:
+						attr |= foregroundIntensity
+					case n == 7:
+						attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4)
+					case n == 22 || n == 25:
+						attr |= foregroundIntensity
+					case n == 27:
+						attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4)
+					case 30 <= n && n <= 37:
+						attr &= backgroundMask
+						if (n-30)&1 != 0 {
+							attr |= foregroundRed
+						}
+						if (n-30)&2 != 0 {
+							attr |= foregroundGreen
+						}
+						if (n-30)&4 != 0 {
+							attr |= foregroundBlue
+						}
+					case n == 38: // set foreground color.
+						if i < len(token)-2 && (token[i+1] == "5" || token[i+1] == "05") {
+							if n256, err := strconv.Atoi(token[i+2]); err == nil {
+								if n256foreAttr == nil {
+									n256setup()
+								}
+								attr &= backgroundMask
+								attr |= n256foreAttr[n256]
+								i += 2
+							}
+						} else {
+							attr = attr & (w.oldattr & backgroundMask)
+						}
+					case n == 39: // reset foreground color.
+						attr &= backgroundMask
+						attr |= w.oldattr & foregroundMask
+					case 40 <= n && n <= 47:
+						attr &= foregroundMask
+						if (n-40)&1 != 0 {
+							attr |= backgroundRed
+						}
+						if (n-40)&2 != 0 {
+							attr |= backgroundGreen
+						}
+						if (n-40)&4 != 0 {
+							attr |= backgroundBlue
+						}
+					case n == 48: // set background color.
+						if i < len(token)-2 && token[i+1] == "5" {
+							if n256, err := strconv.Atoi(token[i+2]); err == nil {
+								if n256backAttr == nil {
+									n256setup()
+								}
+								attr &= foregroundMask
+								attr |= n256backAttr[n256]
+								i += 2
+							}
+						} else {
+							attr = attr & (w.oldattr & foregroundMask)
+						}
+					case n == 49: // reset foreground color.
+						attr &= foregroundMask
+						attr |= w.oldattr & backgroundMask
+					case 90 <= n && n <= 97:
+						attr = (attr & backgroundMask)
+						attr |= foregroundIntensity
+						if (n-90)&1 != 0 {
+							attr |= foregroundRed
+						}
+						if (n-90)&2 != 0 {
+							attr |= foregroundGreen
+						}
+						if (n-90)&4 != 0 {
+							attr |= foregroundBlue
+						}
+					case 100 <= n && n <= 107:
+						attr = (attr & foregroundMask)
+						attr |= backgroundIntensity
+						if (n-100)&1 != 0 {
+							attr |= backgroundRed
+						}
+						if (n-100)&2 != 0 {
+							attr |= backgroundGreen
+						}
+						if (n-100)&4 != 0 {
+							attr |= backgroundBlue
+						}
+					}
+					procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(attr))
+				}
+			}
+		case 'h':
+			var ci consoleCursorInfo
+			cs := buf.String()
+			if cs == "5>" {
+				procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
+				ci.visible = 0
+				procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
+			} else if cs == "?25" {
+				procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
+				ci.visible = 1
+				procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
+			}
+		case 'l':
+			var ci consoleCursorInfo
+			cs := buf.String()
+			if cs == "5>" {
+				procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
+				ci.visible = 1
+				procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
+			} else if cs == "?25" {
+				procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
+				ci.visible = 0
+				procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
+			}
+		case 's':
+			procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
+			w.oldpos = csbi.cursorPosition
+		case 'u':
+			procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&w.oldpos)))
+		}
+	}
+
+	return len(data), nil
+}
+
+type consoleColor struct {
+	rgb       int
+	red       bool
+	green     bool
+	blue      bool
+	intensity bool
+}
+
+func (c consoleColor) foregroundAttr() (attr word) {
+	if c.red {
+		attr |= foregroundRed
+	}
+	if c.green {
+		attr |= foregroundGreen
+	}
+	if c.blue {
+		attr |= foregroundBlue
+	}
+	if c.intensity {
+		attr |= foregroundIntensity
+	}
+	return
+}
+
+func (c consoleColor) backgroundAttr() (attr word) {
+	if c.red {
+		attr |= backgroundRed
+	}
+	if c.green {
+		attr |= backgroundGreen
+	}
+	if c.blue {
+		attr |= backgroundBlue
+	}
+	if c.intensity {
+		attr |= backgroundIntensity
+	}
+	return
+}
+
+var color16 = []consoleColor{
+	{0x000000, false, false, false, false},
+	{0x000080, false, false, true, false},
+	{0x008000, false, true, false, false},
+	{0x008080, false, true, true, false},
+	{0x800000, true, false, false, false},
+	{0x800080, true, false, true, false},
+	{0x808000, true, true, false, false},
+	{0xc0c0c0, true, true, true, false},
+	{0x808080, false, false, false, true},
+	{0x0000ff, false, false, true, true},
+	{0x00ff00, false, true, false, true},
+	{0x00ffff, false, true, true, true},
+	{0xff0000, true, false, false, true},
+	{0xff00ff, true, false, true, true},
+	{0xffff00, true, true, false, true},
+	{0xffffff, true, true, true, true},
+}
+
+type hsv struct {
+	h, s, v float32
+}
+
+func (a hsv) dist(b hsv) float32 {
+	dh := a.h - b.h
+	switch {
+	case dh > 0.5:
+		dh = 1 - dh
+	case dh < -0.5:
+		dh = -1 - dh
+	}
+	ds := a.s - b.s
+	dv := a.v - b.v
+	return float32(math.Sqrt(float64(dh*dh + ds*ds + dv*dv)))
+}
+
+func toHSV(rgb int) hsv {
+	r, g, b := float32((rgb&0xFF0000)>>16)/256.0,
+		float32((rgb&0x00FF00)>>8)/256.0,
+		float32(rgb&0x0000FF)/256.0
+	min, max := minmax3f(r, g, b)
+	h := max - min
+	if h > 0 {
+		if max == r {
+			h = (g - b) / h
+			if h < 0 {
+				h += 6
+			}
+		} else if max == g {
+			h = 2 + (b-r)/h
+		} else {
+			h = 4 + (r-g)/h
+		}
+	}
+	h /= 6.0
+	s := max - min
+	if max != 0 {
+		s /= max
+	}
+	v := max
+	return hsv{h: h, s: s, v: v}
+}
+
+type hsvTable []hsv
+
+func toHSVTable(rgbTable []consoleColor) hsvTable {
+	t := make(hsvTable, len(rgbTable))
+	for i, c := range rgbTable {
+		t[i] = toHSV(c.rgb)
+	}
+	return t
+}
+
+func (t hsvTable) find(rgb int) consoleColor {
+	hsv := toHSV(rgb)
+	n := 7
+	l := float32(5.0)
+	for i, p := range t {
+		d := hsv.dist(p)
+		if d < l {
+			l, n = d, i
+		}
+	}
+	return color16[n]
+}
+
+func minmax3f(a, b, c float32) (min, max float32) {
+	if a < b {
+		if b < c {
+			return a, c
+		} else if a < c {
+			return a, b
+		} else {
+			return c, b
+		}
+	} else {
+		if a < c {
+			return b, c
+		} else if b < c {
+			return b, a
+		} else {
+			return c, a
+		}
+	}
+}
+
+var n256foreAttr []word
+var n256backAttr []word
+
+func n256setup() {
+	n256foreAttr = make([]word, 256)
+	n256backAttr = make([]word, 256)
+	t := toHSVTable(color16)
+	for i, rgb := range color256 {
+		c := t.find(rgb)
+		n256foreAttr[i] = c.foregroundAttr()
+		n256backAttr[i] = c.backgroundAttr()
+	}
+}

+ 55 - 0
vendor/github.com/mattn/go-colorable/noncolorable.go

@@ -0,0 +1,55 @@
+package colorable
+
+import (
+	"bytes"
+	"io"
+)
+
+// NonColorable hold writer but remove escape sequence.
+type NonColorable struct {
+	out io.Writer
+}
+
+// NewNonColorable return new instance of Writer which remove escape sequence from Writer.
+func NewNonColorable(w io.Writer) io.Writer {
+	return &NonColorable{out: w}
+}
+
+// Write write data on console
+func (w *NonColorable) Write(data []byte) (n int, err error) {
+	er := bytes.NewReader(data)
+	var bw [1]byte
+loop:
+	for {
+		c1, err := er.ReadByte()
+		if err != nil {
+			break loop
+		}
+		if c1 != 0x1b {
+			bw[0] = c1
+			w.out.Write(bw[:])
+			continue
+		}
+		c2, err := er.ReadByte()
+		if err != nil {
+			break loop
+		}
+		if c2 != 0x5b {
+			continue
+		}
+
+		var buf bytes.Buffer
+		for {
+			c, err := er.ReadByte()
+			if err != nil {
+				break loop
+			}
+			if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' {
+				break
+			}
+			buf.Write([]byte(string(c)))
+		}
+	}
+
+	return len(data), nil
+}

+ 13 - 0
vendor/github.com/mattn/go-isatty/.travis.yml

@@ -0,0 +1,13 @@
+language: go
+go:
+  - tip
+
+os:
+  - linux
+  - osx
+
+before_install:
+  - go get github.com/mattn/goveralls
+  - go get golang.org/x/tools/cmd/cover
+script:
+  - $HOME/gopath/bin/goveralls -repotoken 3gHdORO5k5ziZcWMBxnd9LrMZaJs8m9x5

+ 9 - 0
vendor/github.com/mattn/go-isatty/LICENSE

@@ -0,0 +1,9 @@
+Copyright (c) Yasuhiro MATSUMOTO <mattn.jp@gmail.com>
+
+MIT License (Expat)
+
+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.

+ 50 - 0
vendor/github.com/mattn/go-isatty/README.md

@@ -0,0 +1,50 @@
+# go-isatty
+
+[![Godoc Reference](https://godoc.org/github.com/mattn/go-isatty?status.svg)](http://godoc.org/github.com/mattn/go-isatty)
+[![Build Status](https://travis-ci.org/mattn/go-isatty.svg?branch=master)](https://travis-ci.org/mattn/go-isatty)
+[![Coverage Status](https://coveralls.io/repos/github/mattn/go-isatty/badge.svg?branch=master)](https://coveralls.io/github/mattn/go-isatty?branch=master)
+[![Go Report Card](https://goreportcard.com/badge/mattn/go-isatty)](https://goreportcard.com/report/mattn/go-isatty)
+
+isatty for golang
+
+## Usage
+
+```go
+package main
+
+import (
+	"fmt"
+	"github.com/mattn/go-isatty"
+	"os"
+)
+
+func main() {
+	if isatty.IsTerminal(os.Stdout.Fd()) {
+		fmt.Println("Is Terminal")
+	} else if isatty.IsCygwinTerminal(os.Stdout.Fd()) {
+		fmt.Println("Is Cygwin/MSYS2 Terminal")
+	} else {
+		fmt.Println("Is Not Terminal")
+	}
+}
+```
+
+## Installation
+
+```
+$ go get github.com/mattn/go-isatty
+```
+
+## License
+
+MIT
+
+## Author
+
+Yasuhiro Matsumoto (a.k.a mattn)
+
+## Thanks
+
+* k-takata: base idea for IsCygwinTerminal
+
+    https://github.com/k-takata/go-iscygpty

+ 2 - 0
vendor/github.com/mattn/go-isatty/doc.go

@@ -0,0 +1,2 @@
+// Package isatty implements interface to isatty
+package isatty

+ 15 - 0
vendor/github.com/mattn/go-isatty/isatty_appengine.go

@@ -0,0 +1,15 @@
+// +build appengine
+
+package isatty
+
+// IsTerminal returns true if the file descriptor is terminal which
+// is always false on on appengine classic which is a sandboxed PaaS.
+func IsTerminal(fd uintptr) bool {
+	return false
+}
+
+// IsCygwinTerminal() return true if the file descriptor is a cygwin or msys2
+// terminal. This is also always false on this environment.
+func IsCygwinTerminal(fd uintptr) bool {
+	return false
+}

+ 18 - 0
vendor/github.com/mattn/go-isatty/isatty_bsd.go

@@ -0,0 +1,18 @@
+// +build darwin freebsd openbsd netbsd dragonfly
+// +build !appengine
+
+package isatty
+
+import (
+	"syscall"
+	"unsafe"
+)
+
+const ioctlReadTermios = syscall.TIOCGETA
+
+// IsTerminal return true if the file descriptor is terminal.
+func IsTerminal(fd uintptr) bool {
+	var termios syscall.Termios
+	_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
+	return err == 0
+}

+ 18 - 0
vendor/github.com/mattn/go-isatty/isatty_linux.go

@@ -0,0 +1,18 @@
+// +build linux
+// +build !appengine,!ppc64,!ppc64le
+
+package isatty
+
+import (
+	"syscall"
+	"unsafe"
+)
+
+const ioctlReadTermios = syscall.TCGETS
+
+// IsTerminal return true if the file descriptor is terminal.
+func IsTerminal(fd uintptr) bool {
+	var termios syscall.Termios
+	_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
+	return err == 0
+}

+ 19 - 0
vendor/github.com/mattn/go-isatty/isatty_linux_ppc64x.go

@@ -0,0 +1,19 @@
+// +build linux
+// +build ppc64 ppc64le
+
+package isatty
+
+import (
+	"unsafe"
+
+	syscall "golang.org/x/sys/unix"
+)
+
+const ioctlReadTermios = syscall.TCGETS
+
+// IsTerminal return true if the file descriptor is terminal.
+func IsTerminal(fd uintptr) bool {
+	var termios syscall.Termios
+	_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
+	return err == 0
+}

+ 10 - 0
vendor/github.com/mattn/go-isatty/isatty_others.go

@@ -0,0 +1,10 @@
+// +build !windows
+// +build !appengine
+
+package isatty
+
+// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2
+// terminal. This is also always false on this environment.
+func IsCygwinTerminal(fd uintptr) bool {
+	return false
+}

+ 16 - 0
vendor/github.com/mattn/go-isatty/isatty_solaris.go

@@ -0,0 +1,16 @@
+// +build solaris
+// +build !appengine
+
+package isatty
+
+import (
+	"golang.org/x/sys/unix"
+)
+
+// IsTerminal returns true if the given file descriptor is a terminal.
+// see: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libbc/libc/gen/common/isatty.c
+func IsTerminal(fd uintptr) bool {
+	var termio unix.Termio
+	err := unix.IoctlSetTermio(int(fd), unix.TCGETA, &termio)
+	return err == nil
+}

+ 94 - 0
vendor/github.com/mattn/go-isatty/isatty_windows.go

@@ -0,0 +1,94 @@
+// +build windows
+// +build !appengine
+
+package isatty
+
+import (
+	"strings"
+	"syscall"
+	"unicode/utf16"
+	"unsafe"
+)
+
+const (
+	fileNameInfo uintptr = 2
+	fileTypePipe         = 3
+)
+
+var (
+	kernel32                         = syscall.NewLazyDLL("kernel32.dll")
+	procGetConsoleMode               = kernel32.NewProc("GetConsoleMode")
+	procGetFileInformationByHandleEx = kernel32.NewProc("GetFileInformationByHandleEx")
+	procGetFileType                  = kernel32.NewProc("GetFileType")
+)
+
+func init() {
+	// Check if GetFileInformationByHandleEx is available.
+	if procGetFileInformationByHandleEx.Find() != nil {
+		procGetFileInformationByHandleEx = nil
+	}
+}
+
+// IsTerminal return true if the file descriptor is terminal.
+func IsTerminal(fd uintptr) bool {
+	var st uint32
+	r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, fd, uintptr(unsafe.Pointer(&st)), 0)
+	return r != 0 && e == 0
+}
+
+// Check pipe name is used for cygwin/msys2 pty.
+// Cygwin/MSYS2 PTY has a name like:
+//   \{cygwin,msys}-XXXXXXXXXXXXXXXX-ptyN-{from,to}-master
+func isCygwinPipeName(name string) bool {
+	token := strings.Split(name, "-")
+	if len(token) < 5 {
+		return false
+	}
+
+	if token[0] != `\msys` && token[0] != `\cygwin` {
+		return false
+	}
+
+	if token[1] == "" {
+		return false
+	}
+
+	if !strings.HasPrefix(token[2], "pty") {
+		return false
+	}
+
+	if token[3] != `from` && token[3] != `to` {
+		return false
+	}
+
+	if token[4] != "master" {
+		return false
+	}
+
+	return true
+}
+
+// IsCygwinTerminal() return true if the file descriptor is a cygwin or msys2
+// terminal.
+func IsCygwinTerminal(fd uintptr) bool {
+	if procGetFileInformationByHandleEx == nil {
+		return false
+	}
+
+	// Cygwin/msys's pty is a pipe.
+	ft, _, e := syscall.Syscall(procGetFileType.Addr(), 1, fd, 0, 0)
+	if ft != fileTypePipe || e != 0 {
+		return false
+	}
+
+	var buf [2 + syscall.MAX_PATH]uint16
+	r, _, e := syscall.Syscall6(procGetFileInformationByHandleEx.Addr(),
+		4, fd, fileNameInfo, uintptr(unsafe.Pointer(&buf)),
+		uintptr(len(buf)*2), 0, 0)
+	if r == 0 || e != 0 {
+		return false
+	}
+
+	l := *(*uint32)(unsafe.Pointer(&buf))
+	return isCygwinPipeName(string(utf16.Decode(buf[2 : 2+l/2])))
+}

+ 15 - 0
vendor/github.com/valyala/bytebufferpool/.travis.yml

@@ -0,0 +1,15 @@
+language: go
+
+go:
+  - 1.6
+
+script:
+  # build test for supported platforms
+  - GOOS=linux go build
+  - GOOS=darwin go build
+  - GOOS=freebsd go build
+  - GOOS=windows go build
+  - GOARCH=386 go build
+
+  # run tests on a standard platform
+  - go test -v ./...

+ 22 - 0
vendor/github.com/valyala/bytebufferpool/LICENSE

@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 Aliaksandr Valialkin, VertaMedia
+
+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.
+

+ 21 - 0
vendor/github.com/valyala/bytebufferpool/README.md

@@ -0,0 +1,21 @@
+[![Build Status](https://travis-ci.org/valyala/bytebufferpool.svg)](https://travis-ci.org/valyala/bytebufferpool)
+[![GoDoc](https://godoc.org/github.com/valyala/bytebufferpool?status.svg)](http://godoc.org/github.com/valyala/bytebufferpool)
+[![Go Report](http://goreportcard.com/badge/valyala/bytebufferpool)](http://goreportcard.com/report/valyala/bytebufferpool)
+
+# bytebufferpool
+
+An implementation of a pool of byte buffers with anti-memory-waste protection.
+
+The pool may waste limited amount of memory due to fragmentation.
+This amount equals to the maximum total size of the byte buffers
+in concurrent use.
+
+# Benchmark results
+Currently bytebufferpool is fastest and most effective buffer pool written in Go.
+
+You can find results [here](https://omgnull.github.io/go-benchmark/buffer/).
+
+# bytebufferpool users
+
+* [fasthttp](https://github.com/valyala/fasthttp)
+* [quicktemplate](https://github.com/valyala/quicktemplate)

+ 111 - 0
vendor/github.com/valyala/bytebufferpool/bytebuffer.go

@@ -0,0 +1,111 @@
+package bytebufferpool
+
+import "io"
+
+// ByteBuffer provides byte buffer, which can be used for minimizing
+// memory allocations.
+//
+// ByteBuffer may be used with functions appending data to the given []byte
+// slice. See example code for details.
+//
+// Use Get for obtaining an empty byte buffer.
+type ByteBuffer struct {
+
+	// B is a byte buffer to use in append-like workloads.
+	// See example code for details.
+	B []byte
+}
+
+// Len returns the size of the byte buffer.
+func (b *ByteBuffer) Len() int {
+	return len(b.B)
+}
+
+// ReadFrom implements io.ReaderFrom.
+//
+// The function appends all the data read from r to b.
+func (b *ByteBuffer) ReadFrom(r io.Reader) (int64, error) {
+	p := b.B
+	nStart := int64(len(p))
+	nMax := int64(cap(p))
+	n := nStart
+	if nMax == 0 {
+		nMax = 64
+		p = make([]byte, nMax)
+	} else {
+		p = p[:nMax]
+	}
+	for {
+		if n == nMax {
+			nMax *= 2
+			bNew := make([]byte, nMax)
+			copy(bNew, p)
+			p = bNew
+		}
+		nn, err := r.Read(p[n:])
+		n += int64(nn)
+		if err != nil {
+			b.B = p[:n]
+			n -= nStart
+			if err == io.EOF {
+				return n, nil
+			}
+			return n, err
+		}
+	}
+}
+
+// WriteTo implements io.WriterTo.
+func (b *ByteBuffer) WriteTo(w io.Writer) (int64, error) {
+	n, err := w.Write(b.B)
+	return int64(n), err
+}
+
+// Bytes returns b.B, i.e. all the bytes accumulated in the buffer.
+//
+// The purpose of this function is bytes.Buffer compatibility.
+func (b *ByteBuffer) Bytes() []byte {
+	return b.B
+}
+
+// Write implements io.Writer - it appends p to ByteBuffer.B
+func (b *ByteBuffer) Write(p []byte) (int, error) {
+	b.B = append(b.B, p...)
+	return len(p), nil
+}
+
+// WriteByte appends the byte c to the buffer.
+//
+// The purpose of this function is bytes.Buffer compatibility.
+//
+// The function always returns nil.
+func (b *ByteBuffer) WriteByte(c byte) error {
+	b.B = append(b.B, c)
+	return nil
+}
+
+// WriteString appends s to ByteBuffer.B.
+func (b *ByteBuffer) WriteString(s string) (int, error) {
+	b.B = append(b.B, s...)
+	return len(s), nil
+}
+
+// Set sets ByteBuffer.B to p.
+func (b *ByteBuffer) Set(p []byte) {
+	b.B = append(b.B[:0], p...)
+}
+
+// SetString sets ByteBuffer.B to s.
+func (b *ByteBuffer) SetString(s string) {
+	b.B = append(b.B[:0], s...)
+}
+
+// String returns string representation of ByteBuffer.B.
+func (b *ByteBuffer) String() string {
+	return string(b.B)
+}
+
+// Reset makes ByteBuffer.B empty.
+func (b *ByteBuffer) Reset() {
+	b.B = b.B[:0]
+}

+ 7 - 0
vendor/github.com/valyala/bytebufferpool/doc.go

@@ -0,0 +1,7 @@
+// Package bytebufferpool implements a pool of byte buffers
+// with anti-fragmentation protection.
+//
+// The pool may waste limited amount of memory due to fragmentation.
+// This amount equals to the maximum total size of the byte buffers
+// in concurrent use.
+package bytebufferpool

+ 151 - 0
vendor/github.com/valyala/bytebufferpool/pool.go

@@ -0,0 +1,151 @@
+package bytebufferpool
+
+import (
+	"sort"
+	"sync"
+	"sync/atomic"
+)
+
+const (
+	minBitSize = 6 // 2**6=64 is a CPU cache line size
+	steps      = 20
+
+	minSize = 1 << minBitSize
+	maxSize = 1 << (minBitSize + steps - 1)
+
+	calibrateCallsThreshold = 42000
+	maxPercentile           = 0.95
+)
+
+// Pool represents byte buffer pool.
+//
+// Distinct pools may be used for distinct types of byte buffers.
+// Properly determined byte buffer types with their own pools may help reducing
+// memory waste.
+type Pool struct {
+	calls       [steps]uint64
+	calibrating uint64
+
+	defaultSize uint64
+	maxSize     uint64
+
+	pool sync.Pool
+}
+
+var defaultPool Pool
+
+// Get returns an empty byte buffer from the pool.
+//
+// Got byte buffer may be returned to the pool via Put call.
+// This reduces the number of memory allocations required for byte buffer
+// management.
+func Get() *ByteBuffer { return defaultPool.Get() }
+
+// Get returns new byte buffer with zero length.
+//
+// The byte buffer may be returned to the pool via Put after the use
+// in order to minimize GC overhead.
+func (p *Pool) Get() *ByteBuffer {
+	v := p.pool.Get()
+	if v != nil {
+		return v.(*ByteBuffer)
+	}
+	return &ByteBuffer{
+		B: make([]byte, 0, atomic.LoadUint64(&p.defaultSize)),
+	}
+}
+
+// Put returns byte buffer to the pool.
+//
+// ByteBuffer.B mustn't be touched after returning it to the pool.
+// Otherwise data races will occur.
+func Put(b *ByteBuffer) { defaultPool.Put(b) }
+
+// Put releases byte buffer obtained via Get to the pool.
+//
+// The buffer mustn't be accessed after returning to the pool.
+func (p *Pool) Put(b *ByteBuffer) {
+	idx := index(len(b.B))
+
+	if atomic.AddUint64(&p.calls[idx], 1) > calibrateCallsThreshold {
+		p.calibrate()
+	}
+
+	maxSize := int(atomic.LoadUint64(&p.maxSize))
+	if maxSize == 0 || cap(b.B) <= maxSize {
+		b.Reset()
+		p.pool.Put(b)
+	}
+}
+
+func (p *Pool) calibrate() {
+	if !atomic.CompareAndSwapUint64(&p.calibrating, 0, 1) {
+		return
+	}
+
+	a := make(callSizes, 0, steps)
+	var callsSum uint64
+	for i := uint64(0); i < steps; i++ {
+		calls := atomic.SwapUint64(&p.calls[i], 0)
+		callsSum += calls
+		a = append(a, callSize{
+			calls: calls,
+			size:  minSize << i,
+		})
+	}
+	sort.Sort(a)
+
+	defaultSize := a[0].size
+	maxSize := defaultSize
+
+	maxSum := uint64(float64(callsSum) * maxPercentile)
+	callsSum = 0
+	for i := 0; i < steps; i++ {
+		if callsSum > maxSum {
+			break
+		}
+		callsSum += a[i].calls
+		size := a[i].size
+		if size > maxSize {
+			maxSize = size
+		}
+	}
+
+	atomic.StoreUint64(&p.defaultSize, defaultSize)
+	atomic.StoreUint64(&p.maxSize, maxSize)
+
+	atomic.StoreUint64(&p.calibrating, 0)
+}
+
+type callSize struct {
+	calls uint64
+	size  uint64
+}
+
+type callSizes []callSize
+
+func (ci callSizes) Len() int {
+	return len(ci)
+}
+
+func (ci callSizes) Less(i, j int) bool {
+	return ci[i].calls > ci[j].calls
+}
+
+func (ci callSizes) Swap(i, j int) {
+	ci[i], ci[j] = ci[j], ci[i]
+}
+
+func index(n int) int {
+	n--
+	n >>= minBitSize
+	idx := 0
+	for n > 0 {
+		n >>= 1
+		idx++
+	}
+	if idx >= steps {
+		idx = steps - 1
+	}
+	return idx
+}

+ 22 - 0
vendor/github.com/valyala/fasttemplate/LICENSE

@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Aliaksandr Valialkin
+
+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.
+

+ 85 - 0
vendor/github.com/valyala/fasttemplate/README.md

@@ -0,0 +1,85 @@
+fasttemplate
+============
+
+Simple and fast template engine for Go.
+
+Fasttemplate peforms only a single task - it substitutes template placeholders
+with user-defined values. At high speed :)
+
+Take a look at [quicktemplate](https://github.com/valyala/quicktemplate) if you  need fast yet powerful html template engine.
+
+*Please note that fasttemplate doesn't do any escaping on template values
+unlike [html/template](http://golang.org/pkg/html/template/) do. So values
+must be properly escaped before passing them to fasttemplate.*
+
+Fasttemplate is faster than [text/template](http://golang.org/pkg/text/template/),
+[strings.Replace](http://golang.org/pkg/strings/#Replace),
+[strings.Replacer](http://golang.org/pkg/strings/#Replacer)
+and [fmt.Fprintf](https://golang.org/pkg/fmt/#Fprintf) on placeholders' substitution.
+
+Below are benchmark results comparing fasttemplate performance to text/template,
+strings.Replace, strings.Replacer and fmt.Fprintf:
+
+```
+$ go test -bench=. -benchmem
+PASS
+BenchmarkFmtFprintf-4                   	 2000000	       790 ns/op	       0 B/op	       0 allocs/op
+BenchmarkStringsReplace-4               	  500000	      3474 ns/op	    2112 B/op	      14 allocs/op
+BenchmarkStringsReplacer-4              	  500000	      2657 ns/op	    2256 B/op	      23 allocs/op
+BenchmarkTextTemplate-4                 	  500000	      3333 ns/op	     336 B/op	      19 allocs/op
+BenchmarkFastTemplateExecuteFunc-4      	 5000000	       349 ns/op	       0 B/op	       0 allocs/op
+BenchmarkFastTemplateExecute-4          	 3000000	       383 ns/op	       0 B/op	       0 allocs/op
+BenchmarkFastTemplateExecuteFuncString-4	 3000000	       549 ns/op	     144 B/op	       1 allocs/op
+BenchmarkFastTemplateExecuteString-4    	 3000000	       572 ns/op	     144 B/op	       1 allocs/op
+BenchmarkFastTemplateExecuteTagFunc-4   	 2000000	       743 ns/op	     144 B/op	       3 allocs/op
+```
+
+
+Docs
+====
+
+See http://godoc.org/github.com/valyala/fasttemplate .
+
+
+Usage
+=====
+
+```go
+	template := "http://{{host}}/?q={{query}}&foo={{bar}}{{bar}}"
+	t := fasttemplate.New(template, "{{", "}}")
+	s := t.ExecuteString(map[string]interface{}{
+		"host":  "google.com",
+		"query": url.QueryEscape("hello=world"),
+		"bar":   "foobar",
+	})
+	fmt.Printf("%s", s)
+
+	// Output:
+	// http://google.com/?q=hello%3Dworld&foo=foobarfoobar
+```
+
+
+Advanced usage
+==============
+
+```go
+	template := "Hello, [user]! You won [prize]!!! [foobar]"
+	t, err := fasttemplate.NewTemplate(template, "[", "]")
+	if err != nil {
+		log.Fatalf("unexpected error when parsing template: %s", err)
+	}
+	s := t.ExecuteFuncString(func(w io.Writer, tag string) (int, error) {
+		switch tag {
+		case "user":
+			return w.Write([]byte("John"))
+		case "prize":
+			return w.Write([]byte("$100500"))
+		default:
+			return w.Write([]byte(fmt.Sprintf("[unknown tag %q]", tag)))
+		}
+	})
+	fmt.Printf("%s", s)
+
+	// Output:
+	// Hello, John! You won $100500!!! [unknown tag "foobar"]
+```

+ 317 - 0
vendor/github.com/valyala/fasttemplate/template.go

@@ -0,0 +1,317 @@
+// Package fasttemplate implements simple and fast template library.
+//
+// Fasttemplate is faster than text/template, strings.Replace
+// and strings.Replacer.
+//
+// Fasttemplate ideally fits for fast and simple placeholders' substitutions.
+package fasttemplate
+
+import (
+	"bytes"
+	"fmt"
+	"github.com/valyala/bytebufferpool"
+	"io"
+)
+
+// ExecuteFunc calls f on each template tag (placeholder) occurrence.
+//
+// Returns the number of bytes written to w.
+//
+// This function is optimized for constantly changing templates.
+// Use Template.ExecuteFunc for frozen templates.
+func ExecuteFunc(template, startTag, endTag string, w io.Writer, f TagFunc) (int64, error) {
+	s := unsafeString2Bytes(template)
+	a := unsafeString2Bytes(startTag)
+	b := unsafeString2Bytes(endTag)
+
+	var nn int64
+	var ni int
+	var err error
+	for {
+		n := bytes.Index(s, a)
+		if n < 0 {
+			break
+		}
+		ni, err = w.Write(s[:n])
+		nn += int64(ni)
+		if err != nil {
+			return nn, err
+		}
+
+		s = s[n+len(a):]
+		n = bytes.Index(s, b)
+		if n < 0 {
+			// cannot find end tag - just write it to the output.
+			ni, _ = w.Write(a)
+			nn += int64(ni)
+			break
+		}
+
+		ni, err = f(w, unsafeBytes2String(s[:n]))
+		nn += int64(ni)
+		s = s[n+len(b):]
+	}
+	ni, err = w.Write(s)
+	nn += int64(ni)
+
+	return nn, err
+}
+
+// Execute substitutes template tags (placeholders) with the corresponding
+// values from the map m and writes the result to the given writer w.
+//
+// Substitution map m may contain values with the following types:
+//   * []byte - the fastest value type
+//   * string - convenient value type
+//   * TagFunc - flexible value type
+//
+// Returns the number of bytes written to w.
+//
+// This function is optimized for constantly changing templates.
+// Use Template.Execute for frozen templates.
+func Execute(template, startTag, endTag string, w io.Writer, m map[string]interface{}) (int64, error) {
+	return ExecuteFunc(template, startTag, endTag, w, func(w io.Writer, tag string) (int, error) { return stdTagFunc(w, tag, m) })
+}
+
+// ExecuteFuncString calls f on each template tag (placeholder) occurrence
+// and substitutes it with the data written to TagFunc's w.
+//
+// Returns the resulting string.
+//
+// This function is optimized for constantly changing templates.
+// Use Template.ExecuteFuncString for frozen templates.
+func ExecuteFuncString(template, startTag, endTag string, f TagFunc) string {
+	tagsCount := bytes.Count(unsafeString2Bytes(template), unsafeString2Bytes(startTag))
+	if tagsCount == 0 {
+		return template
+	}
+
+	bb := byteBufferPool.Get()
+	if _, err := ExecuteFunc(template, startTag, endTag, bb, f); err != nil {
+		panic(fmt.Sprintf("unexpected error: %s", err))
+	}
+	s := string(bb.B)
+	bb.Reset()
+	byteBufferPool.Put(bb)
+	return s
+}
+
+var byteBufferPool bytebufferpool.Pool
+
+// ExecuteString substitutes template tags (placeholders) with the corresponding
+// values from the map m and returns the result.
+//
+// Substitution map m may contain values with the following types:
+//   * []byte - the fastest value type
+//   * string - convenient value type
+//   * TagFunc - flexible value type
+//
+// This function is optimized for constantly changing templates.
+// Use Template.ExecuteString for frozen templates.
+func ExecuteString(template, startTag, endTag string, m map[string]interface{}) string {
+	return ExecuteFuncString(template, startTag, endTag, func(w io.Writer, tag string) (int, error) { return stdTagFunc(w, tag, m) })
+}
+
+// Template implements simple template engine, which can be used for fast
+// tags' (aka placeholders) substitution.
+type Template struct {
+	template string
+	startTag string
+	endTag   string
+
+	texts          [][]byte
+	tags           []string
+	byteBufferPool bytebufferpool.Pool
+}
+
+// New parses the given template using the given startTag and endTag
+// as tag start and tag end.
+//
+// The returned template can be executed by concurrently running goroutines
+// using Execute* methods.
+//
+// New panics if the given template cannot be parsed. Use NewTemplate instead
+// if template may contain errors.
+func New(template, startTag, endTag string) *Template {
+	t, err := NewTemplate(template, startTag, endTag)
+	if err != nil {
+		panic(err)
+	}
+	return t
+}
+
+// NewTemplate parses the given template using the given startTag and endTag
+// as tag start and tag end.
+//
+// The returned template can be executed by concurrently running goroutines
+// using Execute* methods.
+func NewTemplate(template, startTag, endTag string) (*Template, error) {
+	var t Template
+	err := t.Reset(template, startTag, endTag)
+	if err != nil {
+		return nil, err
+	}
+	return &t, nil
+}
+
+// TagFunc can be used as a substitution value in the map passed to Execute*.
+// Execute* functions pass tag (placeholder) name in 'tag' argument.
+//
+// TagFunc must be safe to call from concurrently running goroutines.
+//
+// TagFunc must write contents to w and return the number of bytes written.
+type TagFunc func(w io.Writer, tag string) (int, error)
+
+// Reset resets the template t to new one defined by
+// template, startTag and endTag.
+//
+// Reset allows Template object re-use.
+//
+// Reset may be called only if no other goroutines call t methods at the moment.
+func (t *Template) Reset(template, startTag, endTag string) error {
+	// Keep these vars in t, so GC won't collect them and won't break
+	// vars derived via unsafe*
+	t.template = template
+	t.startTag = startTag
+	t.endTag = endTag
+	t.texts = t.texts[:0]
+	t.tags = t.tags[:0]
+
+	if len(startTag) == 0 {
+		panic("startTag cannot be empty")
+	}
+	if len(endTag) == 0 {
+		panic("endTag cannot be empty")
+	}
+
+	s := unsafeString2Bytes(template)
+	a := unsafeString2Bytes(startTag)
+	b := unsafeString2Bytes(endTag)
+
+	tagsCount := bytes.Count(s, a)
+	if tagsCount == 0 {
+		return nil
+	}
+
+	if tagsCount+1 > cap(t.texts) {
+		t.texts = make([][]byte, 0, tagsCount+1)
+	}
+	if tagsCount > cap(t.tags) {
+		t.tags = make([]string, 0, tagsCount)
+	}
+
+	for {
+		n := bytes.Index(s, a)
+		if n < 0 {
+			t.texts = append(t.texts, s)
+			break
+		}
+		t.texts = append(t.texts, s[:n])
+
+		s = s[n+len(a):]
+		n = bytes.Index(s, b)
+		if n < 0 {
+			return fmt.Errorf("Cannot find end tag=%q in the template=%q starting from %q", endTag, template, s)
+		}
+
+		t.tags = append(t.tags, unsafeBytes2String(s[:n]))
+		s = s[n+len(b):]
+	}
+
+	return nil
+}
+
+// ExecuteFunc calls f on each template tag (placeholder) occurrence.
+//
+// Returns the number of bytes written to w.
+//
+// This function is optimized for frozen templates.
+// Use ExecuteFunc for constantly changing templates.
+func (t *Template) ExecuteFunc(w io.Writer, f TagFunc) (int64, error) {
+	var nn int64
+
+	n := len(t.texts) - 1
+	if n == -1 {
+		ni, err := w.Write(unsafeString2Bytes(t.template))
+		return int64(ni), err
+	}
+
+	for i := 0; i < n; i++ {
+		ni, err := w.Write(t.texts[i])
+		nn += int64(ni)
+		if err != nil {
+			return nn, err
+		}
+
+		ni, err = f(w, t.tags[i])
+		nn += int64(ni)
+		if err != nil {
+			return nn, err
+		}
+	}
+	ni, err := w.Write(t.texts[n])
+	nn += int64(ni)
+	return nn, err
+}
+
+// Execute substitutes template tags (placeholders) with the corresponding
+// values from the map m and writes the result to the given writer w.
+//
+// Substitution map m may contain values with the following types:
+//   * []byte - the fastest value type
+//   * string - convenient value type
+//   * TagFunc - flexible value type
+//
+// Returns the number of bytes written to w.
+func (t *Template) Execute(w io.Writer, m map[string]interface{}) (int64, error) {
+	return t.ExecuteFunc(w, func(w io.Writer, tag string) (int, error) { return stdTagFunc(w, tag, m) })
+}
+
+// ExecuteFuncString calls f on each template tag (placeholder) occurrence
+// and substitutes it with the data written to TagFunc's w.
+//
+// Returns the resulting string.
+//
+// This function is optimized for frozen templates.
+// Use ExecuteFuncString for constantly changing templates.
+func (t *Template) ExecuteFuncString(f TagFunc) string {
+	bb := t.byteBufferPool.Get()
+	if _, err := t.ExecuteFunc(bb, f); err != nil {
+		panic(fmt.Sprintf("unexpected error: %s", err))
+	}
+	s := string(bb.Bytes())
+	bb.Reset()
+	t.byteBufferPool.Put(bb)
+	return s
+}
+
+// ExecuteString substitutes template tags (placeholders) with the corresponding
+// values from the map m and returns the result.
+//
+// Substitution map m may contain values with the following types:
+//   * []byte - the fastest value type
+//   * string - convenient value type
+//   * TagFunc - flexible value type
+//
+// This function is optimized for frozen templates.
+// Use ExecuteString for constantly changing templates.
+func (t *Template) ExecuteString(m map[string]interface{}) string {
+	return t.ExecuteFuncString(func(w io.Writer, tag string) (int, error) { return stdTagFunc(w, tag, m) })
+}
+
+func stdTagFunc(w io.Writer, tag string, m map[string]interface{}) (int, error) {
+	v := m[tag]
+	if v == nil {
+		return 0, nil
+	}
+	switch value := v.(type) {
+	case []byte:
+		return w.Write(value)
+	case string:
+		return w.Write([]byte(value))
+	case TagFunc:
+		return value(w, tag)
+	default:
+		panic(fmt.Sprintf("tag=%q contains unexpected value type=%#v. Expected []byte, string or TagFunc", tag, v))
+	}
+}

Some files were not shown because too many files changed in this diff