Explorar o código

update vendor

lijian %!s(int64=6) %!d(string=hai) anos
pai
achega
875ea1478d
Modificáronse 100 ficheiros con 11791 adicións e 0 borrados
  1. 19 0
      vendor/github.com/boj/redistore/LICENSE
  2. 53 0
      vendor/github.com/boj/redistore/README.md
  3. 4 0
      vendor/github.com/boj/redistore/doc.go
  4. 7 0
      vendor/github.com/boj/redistore/go.mod
  5. 361 0
      vendor/github.com/boj/redistore/redistore.go
  6. 8 0
      vendor/github.com/dgrijalva/jwt-go/LICENSE
  7. 97 0
      vendor/github.com/dgrijalva/jwt-go/MIGRATION_GUIDE.md
  8. 100 0
      vendor/github.com/dgrijalva/jwt-go/README.md
  9. 118 0
      vendor/github.com/dgrijalva/jwt-go/VERSION_HISTORY.md
  10. 134 0
      vendor/github.com/dgrijalva/jwt-go/claims.go
  11. 4 0
      vendor/github.com/dgrijalva/jwt-go/doc.go
  12. 148 0
      vendor/github.com/dgrijalva/jwt-go/ecdsa.go
  13. 67 0
      vendor/github.com/dgrijalva/jwt-go/ecdsa_utils.go
  14. 59 0
      vendor/github.com/dgrijalva/jwt-go/errors.go
  15. 95 0
      vendor/github.com/dgrijalva/jwt-go/hmac.go
  16. 94 0
      vendor/github.com/dgrijalva/jwt-go/map_claims.go
  17. 52 0
      vendor/github.com/dgrijalva/jwt-go/none.go
  18. 148 0
      vendor/github.com/dgrijalva/jwt-go/parser.go
  19. 101 0
      vendor/github.com/dgrijalva/jwt-go/rsa.go
  20. 126 0
      vendor/github.com/dgrijalva/jwt-go/rsa_pss.go
  21. 101 0
      vendor/github.com/dgrijalva/jwt-go/rsa_utils.go
  22. 35 0
      vendor/github.com/dgrijalva/jwt-go/signing_method.go
  23. 108 0
      vendor/github.com/dgrijalva/jwt-go/token.go
  24. 175 0
      vendor/github.com/gomodule/redigo/LICENSE
  25. 55 0
      vendor/github.com/gomodule/redigo/redis/commandinfo.go
  26. 684 0
      vendor/github.com/gomodule/redigo/redis/conn.go
  27. 177 0
      vendor/github.com/gomodule/redigo/redis/doc.go
  28. 27 0
      vendor/github.com/gomodule/redigo/redis/go16.go
  29. 29 0
      vendor/github.com/gomodule/redigo/redis/go17.go
  30. 9 0
      vendor/github.com/gomodule/redigo/redis/go18.go
  31. 146 0
      vendor/github.com/gomodule/redigo/redis/log.go
  32. 560 0
      vendor/github.com/gomodule/redigo/redis/pool.go
  33. 35 0
      vendor/github.com/gomodule/redigo/redis/pool17.go
  34. 148 0
      vendor/github.com/gomodule/redigo/redis/pubsub.go
  35. 117 0
      vendor/github.com/gomodule/redigo/redis/redis.go
  36. 479 0
      vendor/github.com/gomodule/redigo/redis/reply.go
  37. 585 0
      vendor/github.com/gomodule/redigo/redis/scan.go
  38. 91 0
      vendor/github.com/gomodule/redigo/redis/script.go
  39. 27 0
      vendor/github.com/gorilla/context/LICENSE
  40. 10 0
      vendor/github.com/gorilla/context/README.md
  41. 143 0
      vendor/github.com/gorilla/context/context.go
  42. 88 0
      vendor/github.com/gorilla/context/doc.go
  43. 19 0
      vendor/github.com/gorilla/securecookie/AUTHORS
  44. 27 0
      vendor/github.com/gorilla/securecookie/LICENSE
  45. 82 0
      vendor/github.com/gorilla/securecookie/README.md
  46. 61 0
      vendor/github.com/gorilla/securecookie/doc.go
  47. 25 0
      vendor/github.com/gorilla/securecookie/fuzz.go
  48. 1 0
      vendor/github.com/gorilla/securecookie/go.mod
  49. 650 0
      vendor/github.com/gorilla/securecookie/securecookie.go
  50. 43 0
      vendor/github.com/gorilla/sessions/AUTHORS
  51. 27 0
      vendor/github.com/gorilla/sessions/LICENSE
  52. 95 0
      vendor/github.com/gorilla/sessions/README.md
  53. 202 0
      vendor/github.com/gorilla/sessions/doc.go
  54. 6 0
      vendor/github.com/gorilla/sessions/go.mod
  55. 102 0
      vendor/github.com/gorilla/sessions/lex.go
  56. 18 0
      vendor/github.com/gorilla/sessions/options.go
  57. 22 0
      vendor/github.com/gorilla/sessions/options_go111.go
  58. 226 0
      vendor/github.com/gorilla/sessions/sessions.go
  59. 292 0
      vendor/github.com/gorilla/sessions/store.go
  60. 20 0
      vendor/github.com/martini-contrib/sessions/LICENSE
  61. 41 0
      vendor/github.com/martini-contrib/sessions/README.md
  62. 45 0
      vendor/github.com/martini-contrib/sessions/cookie_store.go
  63. 50 0
      vendor/github.com/martini-contrib/sessions/redis_store.go
  64. 166 0
      vendor/github.com/martini-contrib/sessions/sessions.go
  65. 1 0
      vendor/github.com/martini-contrib/sessions/wercker.yml
  66. 22 0
      vendor/github.com/xyproto/cookie/LICENSE
  67. 19 0
      vendor/github.com/xyproto/cookie/README.md
  68. 21 0
      vendor/github.com/xyproto/cookie/check.sh
  69. 143 0
      vendor/github.com/xyproto/cookie/cookie.go
  70. 49 0
      vendor/github.com/xyproto/cookie/randomstring.go
  71. 21 0
      vendor/github.com/xyproto/permissionsql/LICENSE
  72. 335 0
      vendor/github.com/xyproto/permissionsql/README.md
  73. 11 0
      vendor/github.com/xyproto/permissionsql/TODO.md
  74. 18 0
      vendor/github.com/xyproto/permissionsql/go.mod
  75. 38 0
      vendor/github.com/xyproto/permissionsql/go.sum
  76. 48 0
      vendor/github.com/xyproto/permissionsql/hashing.go
  77. 183 0
      vendor/github.com/xyproto/permissionsql/permissionsql.go
  78. 619 0
      vendor/github.com/xyproto/permissionsql/userstate.go
  79. 22 0
      vendor/github.com/xyproto/pinterface/LICENSE
  80. 16 0
      vendor/github.com/xyproto/pinterface/README.md
  81. 1 0
      vendor/github.com/xyproto/pinterface/go.mod
  82. 142 0
      vendor/github.com/xyproto/pinterface/pinterface.go
  83. 21 0
      vendor/github.com/xyproto/simplemaria/LICENSE
  84. 91 0
      vendor/github.com/xyproto/simplemaria/README.md
  85. 3 0
      vendor/github.com/xyproto/simplemaria/TODO.md
  86. 31 0
      vendor/github.com/xyproto/simplemaria/creator.go
  87. 48 0
      vendor/github.com/xyproto/simplemaria/encdec.go
  88. 10 0
      vendor/github.com/xyproto/simplemaria/go.mod
  89. 14 0
      vendor/github.com/xyproto/simplemaria/go.sum
  90. 145 0
      vendor/github.com/xyproto/simplemaria/helpers.go
  91. 799 0
      vendor/github.com/xyproto/simplemaria/simplemaria.go
  92. 35 0
      vendor/golang.org/x/crypto/bcrypt/base64.go
  93. 295 0
      vendor/golang.org/x/crypto/bcrypt/bcrypt.go
  94. 159 0
      vendor/golang.org/x/crypto/blowfish/block.go
  95. 91 0
      vendor/golang.org/x/crypto/blowfish/cipher.go
  96. 199 0
      vendor/golang.org/x/crypto/blowfish/const.go
  97. 202 0
      vendor/google.golang.org/appengine/LICENSE
  98. 62 0
      vendor/google.golang.org/appengine/cloudsql/cloudsql.go
  99. 17 0
      vendor/google.golang.org/appengine/cloudsql/cloudsql_classic.go
  100. 16 0
      vendor/google.golang.org/appengine/cloudsql/cloudsql_vm.go

+ 19 - 0
vendor/github.com/boj/redistore/LICENSE

@@ -0,0 +1,19 @@
+Copyright (c) 2013 Brian Jones
+ 
+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.

+ 53 - 0
vendor/github.com/boj/redistore/README.md

@@ -0,0 +1,53 @@
+# redistore
+
+[![GoDoc](https://godoc.org/github.com/boj/redistore?status.svg)](https://godoc.org/github.com/boj/redistore)
+[![Build Status](https://travis-ci.org/boj/redistore.svg?branch=master)](https://travis-ci.org/boj/redistore)
+
+A session store backend for [gorilla/sessions](http://www.gorillatoolkit.org/pkg/sessions) - [src](https://github.com/gorilla/sessions).
+
+## Requirements
+
+Depends on the [Redigo](https://github.com/gomodule/redigo) Redis library.
+
+## Installation
+
+    go get gopkg.in/boj/redistore.v1
+
+## Documentation
+
+Available on [godoc.org](http://www.godoc.org/gopkg.in/boj/redistore.v1).
+
+See http://www.gorillatoolkit.org/pkg/sessions for full documentation on underlying interface.
+
+### Example
+``` go
+// Fetch new store.
+store, err := NewRediStore(10, "tcp", ":6379", "", []byte("secret-key"))
+if err != nil {
+	panic(err)
+}
+defer store.Close()
+
+// Get a session.
+session, err = store.Get(req, "session-key")
+if err != nil {
+	log.Error(err.Error())
+}
+
+// Add a value.
+session.Values["foo"] = "bar"
+
+// Save.
+if err = sessions.Save(req, rsp); err != nil {
+	t.Fatalf("Error saving session: %v", err)
+}
+
+// Delete session.
+session.Options.MaxAge = -1
+if err = sessions.Save(req, rsp); err != nil {
+	t.Fatalf("Error saving session: %v", err)
+}
+
+// Change session storage configuration for MaxAge = 10 days.
+store.SetMaxAge(10 * 24 * 3600)
+```

+ 4 - 0
vendor/github.com/boj/redistore/doc.go

@@ -0,0 +1,4 @@
+/*
+Package redistore is a session store backend for gorilla/sessions
+*/
+package redistore

+ 7 - 0
vendor/github.com/boj/redistore/go.mod

@@ -0,0 +1,7 @@
+module github.com/boj/redistore
+
+require (
+	github.com/gomodule/redigo v2.0.0+incompatible
+	github.com/gorilla/securecookie v1.1.1
+	github.com/gorilla/sessions v1.1.1
+)

+ 361 - 0
vendor/github.com/boj/redistore/redistore.go

@@ -0,0 +1,361 @@
+// Copyright 2012 Brian "bojo" Jones. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package redistore
+
+import (
+	"bytes"
+	"encoding/base32"
+	"encoding/gob"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"net/http"
+	"strings"
+	"time"
+
+	"github.com/gomodule/redigo/redis"
+	"github.com/gorilla/securecookie"
+	"github.com/gorilla/sessions"
+)
+
+// Amount of time for cookies/redis keys to expire.
+var sessionExpire = 86400 * 30
+
+// SessionSerializer provides an interface hook for alternative serializers
+type SessionSerializer interface {
+	Deserialize(d []byte, ss *sessions.Session) error
+	Serialize(ss *sessions.Session) ([]byte, error)
+}
+
+// JSONSerializer encode the session map to JSON.
+type JSONSerializer struct{}
+
+// Serialize to JSON. Will err if there are unmarshalable key values
+func (s JSONSerializer) Serialize(ss *sessions.Session) ([]byte, error) {
+	m := make(map[string]interface{}, len(ss.Values))
+	for k, v := range ss.Values {
+		ks, ok := k.(string)
+		if !ok {
+			err := fmt.Errorf("Non-string key value, cannot serialize session to JSON: %v", k)
+			fmt.Printf("redistore.JSONSerializer.serialize() Error: %v", err)
+			return nil, err
+		}
+		m[ks] = v
+	}
+	return json.Marshal(m)
+}
+
+// Deserialize back to map[string]interface{}
+func (s JSONSerializer) Deserialize(d []byte, ss *sessions.Session) error {
+	m := make(map[string]interface{})
+	err := json.Unmarshal(d, &m)
+	if err != nil {
+		fmt.Printf("redistore.JSONSerializer.deserialize() Error: %v", err)
+		return err
+	}
+	for k, v := range m {
+		ss.Values[k] = v
+	}
+	return nil
+}
+
+// GobSerializer uses gob package to encode the session map
+type GobSerializer struct{}
+
+// Serialize using gob
+func (s GobSerializer) Serialize(ss *sessions.Session) ([]byte, error) {
+	buf := new(bytes.Buffer)
+	enc := gob.NewEncoder(buf)
+	err := enc.Encode(ss.Values)
+	if err == nil {
+		return buf.Bytes(), nil
+	}
+	return nil, err
+}
+
+// Deserialize back to map[interface{}]interface{}
+func (s GobSerializer) Deserialize(d []byte, ss *sessions.Session) error {
+	dec := gob.NewDecoder(bytes.NewBuffer(d))
+	return dec.Decode(&ss.Values)
+}
+
+// RediStore stores sessions in a redis backend.
+type RediStore struct {
+	Pool          *redis.Pool
+	Codecs        []securecookie.Codec
+	Options       *sessions.Options // default configuration
+	DefaultMaxAge int               // default Redis TTL for a MaxAge == 0 session
+	maxLength     int
+	keyPrefix     string
+	serializer    SessionSerializer
+}
+
+// SetMaxLength sets RediStore.maxLength if the `l` argument is greater or equal 0
+// maxLength restricts the maximum length of new sessions to l.
+// If l is 0 there is no limit to the size of a session, use with caution.
+// The default for a new RediStore is 4096. Redis allows for max.
+// value sizes of up to 512MB (http://redis.io/topics/data-types)
+// Default: 4096,
+func (s *RediStore) SetMaxLength(l int) {
+	if l >= 0 {
+		s.maxLength = l
+	}
+}
+
+// SetKeyPrefix set the prefix
+func (s *RediStore) SetKeyPrefix(p string) {
+	s.keyPrefix = p
+}
+
+// SetSerializer sets the serializer
+func (s *RediStore) SetSerializer(ss SessionSerializer) {
+	s.serializer = ss
+}
+
+// SetMaxAge restricts the maximum age, in seconds, of the session record
+// both in database and a browser. This is to change session storage configuration.
+// If you want just to remove session use your session `s` object and change it's
+// `Options.MaxAge` to -1, as specified in
+//    http://godoc.org/github.com/gorilla/sessions#Options
+//
+// Default is the one provided by this package value - `sessionExpire`.
+// Set it to 0 for no restriction.
+// Because we use `MaxAge` also in SecureCookie crypting algorithm you should
+// use this function to change `MaxAge` value.
+func (s *RediStore) SetMaxAge(v int) {
+	var c *securecookie.SecureCookie
+	var ok bool
+	s.Options.MaxAge = v
+	for i := range s.Codecs {
+		if c, ok = s.Codecs[i].(*securecookie.SecureCookie); ok {
+			c.MaxAge(v)
+		} else {
+			fmt.Printf("Can't change MaxAge on codec %v\n", s.Codecs[i])
+		}
+	}
+}
+
+func dial(network, address, password string) (redis.Conn, error) {
+	c, err := redis.Dial(network, address)
+	if err != nil {
+		return nil, err
+	}
+	if password != "" {
+		if _, err := c.Do("AUTH", password); err != nil {
+			c.Close()
+			return nil, err
+		}
+	}
+	return c, err
+}
+
+// NewRediStore returns a new RediStore.
+// size: maximum number of idle connections.
+func NewRediStore(size int, network, address, password string, keyPairs ...[]byte) (*RediStore, error) {
+	return NewRediStoreWithPool(&redis.Pool{
+		MaxIdle:     size,
+		IdleTimeout: 240 * time.Second,
+		TestOnBorrow: func(c redis.Conn, t time.Time) error {
+			_, err := c.Do("PING")
+			return err
+		},
+		Dial: func() (redis.Conn, error) {
+			return dial(network, address, password)
+		},
+	}, keyPairs...)
+}
+
+func dialWithDB(network, address, password, DB string) (redis.Conn, error) {
+	c, err := dial(network, address, password)
+	if err != nil {
+		return nil, err
+	}
+	if _, err := c.Do("SELECT", DB); err != nil {
+		c.Close()
+		return nil, err
+	}
+	return c, err
+}
+
+// NewRediStoreWithDB - like NewRedisStore but accepts `DB` parameter to select
+// redis DB instead of using the default one ("0")
+func NewRediStoreWithDB(size int, network, address, password, DB string, keyPairs ...[]byte) (*RediStore, error) {
+	return NewRediStoreWithPool(&redis.Pool{
+		MaxIdle:     size,
+		IdleTimeout: 240 * time.Second,
+		TestOnBorrow: func(c redis.Conn, t time.Time) error {
+			_, err := c.Do("PING")
+			return err
+		},
+		Dial: func() (redis.Conn, error) {
+			return dialWithDB(network, address, password, DB)
+		},
+	}, keyPairs...)
+}
+
+// NewRediStoreWithPool instantiates a RediStore with a *redis.Pool passed in.
+func NewRediStoreWithPool(pool *redis.Pool, keyPairs ...[]byte) (*RediStore, error) {
+	rs := &RediStore{
+		// http://godoc.org/github.com/gomodule/redigo/redis#Pool
+		Pool:   pool,
+		Codecs: securecookie.CodecsFromPairs(keyPairs...),
+		Options: &sessions.Options{
+			Path:   "/",
+			MaxAge: sessionExpire,
+		},
+		DefaultMaxAge: 60 * 20, // 20 minutes seems like a reasonable default
+		maxLength:     4096,
+		keyPrefix:     "session_",
+		serializer:    GobSerializer{},
+	}
+	_, err := rs.ping()
+	return rs, err
+}
+
+// Close closes the underlying *redis.Pool
+func (s *RediStore) Close() error {
+	return s.Pool.Close()
+}
+
+// Get returns a session for the given name after adding it to the registry.
+//
+// See gorilla/sessions FilesystemStore.Get().
+func (s *RediStore) Get(r *http.Request, name string) (*sessions.Session, error) {
+	return sessions.GetRegistry(r).Get(s, name)
+}
+
+// New returns a session for the given name without adding it to the registry.
+//
+// See gorilla/sessions FilesystemStore.New().
+func (s *RediStore) New(r *http.Request, name string) (*sessions.Session, error) {
+	var (
+		err error
+		ok  bool
+	)
+	session := sessions.NewSession(s, name)
+	// make a copy
+	options := *s.Options
+	session.Options = &options
+	session.IsNew = true
+	if c, errCookie := r.Cookie(name); errCookie == nil {
+		err = securecookie.DecodeMulti(name, c.Value, &session.ID, s.Codecs...)
+		if err == nil {
+			ok, err = s.load(session)
+			session.IsNew = !(err == nil && ok) // not new if no error and data available
+		}
+	}
+	return session, err
+}
+
+// Save adds a single session to the response.
+func (s *RediStore) Save(r *http.Request, w http.ResponseWriter, session *sessions.Session) error {
+	// Marked for deletion.
+	if session.Options.MaxAge <= 0 {
+		if err := s.delete(session); err != nil {
+			return err
+		}
+		http.SetCookie(w, sessions.NewCookie(session.Name(), "", session.Options))
+	} else {
+		// Build an alphanumeric key for the redis store.
+		if session.ID == "" {
+			session.ID = strings.TrimRight(base32.StdEncoding.EncodeToString(securecookie.GenerateRandomKey(32)), "=")
+		}
+		if err := s.save(session); err != nil {
+			return err
+		}
+		encoded, err := securecookie.EncodeMulti(session.Name(), session.ID, s.Codecs...)
+		if err != nil {
+			return err
+		}
+		http.SetCookie(w, sessions.NewCookie(session.Name(), encoded, session.Options))
+	}
+	return nil
+}
+
+// Delete removes the session from redis, and sets the cookie to expire.
+//
+// WARNING: This method should be considered deprecated since it is not exposed via the gorilla/sessions interface.
+// Set session.Options.MaxAge = -1 and call Save instead. - July 18th, 2013
+func (s *RediStore) Delete(r *http.Request, w http.ResponseWriter, session *sessions.Session) error {
+	conn := s.Pool.Get()
+	defer conn.Close()
+	if _, err := conn.Do("DEL", s.keyPrefix+session.ID); err != nil {
+		return err
+	}
+	// Set cookie to expire.
+	options := *session.Options
+	options.MaxAge = -1
+	http.SetCookie(w, sessions.NewCookie(session.Name(), "", &options))
+	// Clear session values.
+	for k := range session.Values {
+		delete(session.Values, k)
+	}
+	return nil
+}
+
+// ping does an internal ping against a server to check if it is alive.
+func (s *RediStore) ping() (bool, error) {
+	conn := s.Pool.Get()
+	defer conn.Close()
+	data, err := conn.Do("PING")
+	if err != nil || data == nil {
+		return false, err
+	}
+	return (data == "PONG"), nil
+}
+
+// save stores the session in redis.
+func (s *RediStore) save(session *sessions.Session) error {
+	b, err := s.serializer.Serialize(session)
+	if err != nil {
+		return err
+	}
+	if s.maxLength != 0 && len(b) > s.maxLength {
+		return errors.New("SessionStore: the value to store is too big")
+	}
+	conn := s.Pool.Get()
+	defer conn.Close()
+	if err = conn.Err(); err != nil {
+		return err
+	}
+	age := session.Options.MaxAge
+	if age == 0 {
+		age = s.DefaultMaxAge
+	}
+	_, err = conn.Do("SETEX", s.keyPrefix+session.ID, age, b)
+	return err
+}
+
+// load reads the session from redis.
+// returns true if there is a sessoin data in DB
+func (s *RediStore) load(session *sessions.Session) (bool, error) {
+	conn := s.Pool.Get()
+	defer conn.Close()
+	if err := conn.Err(); err != nil {
+		return false, err
+	}
+	data, err := conn.Do("GET", s.keyPrefix+session.ID)
+	if err != nil {
+		return false, err
+	}
+	if data == nil {
+		return false, nil // no data was associated with this key
+	}
+	b, err := redis.Bytes(data, err)
+	if err != nil {
+		return false, err
+	}
+	return true, s.serializer.Deserialize(b, session)
+}
+
+// delete removes keys from redis if MaxAge<0
+func (s *RediStore) delete(session *sessions.Session) error {
+	conn := s.Pool.Get()
+	defer conn.Close()
+	if _, err := conn.Do("DEL", s.keyPrefix+session.ID); err != nil {
+		return err
+	}
+	return nil
+}

+ 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/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)
+}

+ 175 - 0
vendor/github.com/gomodule/redigo/LICENSE

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

+ 55 - 0
vendor/github.com/gomodule/redigo/redis/commandinfo.go

@@ -0,0 +1,55 @@
+// Copyright 2014 Gary Burd
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package redis
+
+import (
+	"strings"
+)
+
+const (
+	connectionWatchState = 1 << iota
+	connectionMultiState
+	connectionSubscribeState
+	connectionMonitorState
+)
+
+type commandInfo struct {
+	// Set or Clear these states on connection.
+	Set, Clear int
+}
+
+var commandInfos = map[string]commandInfo{
+	"WATCH":      {Set: connectionWatchState},
+	"UNWATCH":    {Clear: connectionWatchState},
+	"MULTI":      {Set: connectionMultiState},
+	"EXEC":       {Clear: connectionWatchState | connectionMultiState},
+	"DISCARD":    {Clear: connectionWatchState | connectionMultiState},
+	"PSUBSCRIBE": {Set: connectionSubscribeState},
+	"SUBSCRIBE":  {Set: connectionSubscribeState},
+	"MONITOR":    {Set: connectionMonitorState},
+}
+
+func init() {
+	for n, ci := range commandInfos {
+		commandInfos[strings.ToLower(n)] = ci
+	}
+}
+
+func lookupCommandInfo(commandName string) commandInfo {
+	if ci, ok := commandInfos[commandName]; ok {
+		return ci
+	}
+	return commandInfos[strings.ToUpper(commandName)]
+}

+ 684 - 0
vendor/github.com/gomodule/redigo/redis/conn.go

@@ -0,0 +1,684 @@
+// Copyright 2012 Gary Burd
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package redis
+
+import (
+	"bufio"
+	"bytes"
+	"crypto/tls"
+	"errors"
+	"fmt"
+	"io"
+	"net"
+	"net/url"
+	"regexp"
+	"strconv"
+	"sync"
+	"time"
+)
+
+var (
+	_ ConnWithTimeout = (*conn)(nil)
+)
+
+// conn is the low-level implementation of Conn
+type conn struct {
+	// Shared
+	mu      sync.Mutex
+	pending int
+	err     error
+	conn    net.Conn
+
+	// Read
+	readTimeout time.Duration
+	br          *bufio.Reader
+
+	// Write
+	writeTimeout time.Duration
+	bw           *bufio.Writer
+
+	// Scratch space for formatting argument length.
+	// '*' or '$', length, "\r\n"
+	lenScratch [32]byte
+
+	// Scratch space for formatting integers and floats.
+	numScratch [40]byte
+}
+
+// DialTimeout acts like Dial but takes timeouts for establishing the
+// connection to the server, writing a command and reading a reply.
+//
+// Deprecated: Use Dial with options instead.
+func DialTimeout(network, address string, connectTimeout, readTimeout, writeTimeout time.Duration) (Conn, error) {
+	return Dial(network, address,
+		DialConnectTimeout(connectTimeout),
+		DialReadTimeout(readTimeout),
+		DialWriteTimeout(writeTimeout))
+}
+
+// DialOption specifies an option for dialing a Redis server.
+type DialOption struct {
+	f func(*dialOptions)
+}
+
+type dialOptions struct {
+	readTimeout  time.Duration
+	writeTimeout time.Duration
+	dialer       *net.Dialer
+	dial         func(network, addr string) (net.Conn, error)
+	db           int
+	password     string
+	useTLS       bool
+	skipVerify   bool
+	tlsConfig    *tls.Config
+}
+
+// DialReadTimeout specifies the timeout for reading a single command reply.
+func DialReadTimeout(d time.Duration) DialOption {
+	return DialOption{func(do *dialOptions) {
+		do.readTimeout = d
+	}}
+}
+
+// DialWriteTimeout specifies the timeout for writing a single command.
+func DialWriteTimeout(d time.Duration) DialOption {
+	return DialOption{func(do *dialOptions) {
+		do.writeTimeout = d
+	}}
+}
+
+// DialConnectTimeout specifies the timeout for connecting to the Redis server when
+// no DialNetDial option is specified.
+func DialConnectTimeout(d time.Duration) DialOption {
+	return DialOption{func(do *dialOptions) {
+		do.dialer.Timeout = d
+	}}
+}
+
+// DialKeepAlive specifies the keep-alive period for TCP connections to the Redis server
+// when no DialNetDial option is specified.
+// If zero, keep-alives are not enabled. If no DialKeepAlive option is specified then
+// the default of 5 minutes is used to ensure that half-closed TCP sessions are detected.
+func DialKeepAlive(d time.Duration) DialOption {
+	return DialOption{func(do *dialOptions) {
+		do.dialer.KeepAlive = d
+	}}
+}
+
+// DialNetDial specifies a custom dial function for creating TCP
+// connections, otherwise a net.Dialer customized via the other options is used.
+// DialNetDial overrides DialConnectTimeout and DialKeepAlive.
+func DialNetDial(dial func(network, addr string) (net.Conn, error)) DialOption {
+	return DialOption{func(do *dialOptions) {
+		do.dial = dial
+	}}
+}
+
+// DialDatabase specifies the database to select when dialing a connection.
+func DialDatabase(db int) DialOption {
+	return DialOption{func(do *dialOptions) {
+		do.db = db
+	}}
+}
+
+// DialPassword specifies the password to use when connecting to
+// the Redis server.
+func DialPassword(password string) DialOption {
+	return DialOption{func(do *dialOptions) {
+		do.password = password
+	}}
+}
+
+// DialTLSConfig specifies the config to use when a TLS connection is dialed.
+// Has no effect when not dialing a TLS connection.
+func DialTLSConfig(c *tls.Config) DialOption {
+	return DialOption{func(do *dialOptions) {
+		do.tlsConfig = c
+	}}
+}
+
+// DialTLSSkipVerify disables server name verification when connecting over
+// TLS. Has no effect when not dialing a TLS connection.
+func DialTLSSkipVerify(skip bool) DialOption {
+	return DialOption{func(do *dialOptions) {
+		do.skipVerify = skip
+	}}
+}
+
+// DialUseTLS specifies whether TLS should be used when connecting to the
+// server. This option is ignore by DialURL.
+func DialUseTLS(useTLS bool) DialOption {
+	return DialOption{func(do *dialOptions) {
+		do.useTLS = useTLS
+	}}
+}
+
+// Dial connects to the Redis server at the given network and
+// address using the specified options.
+func Dial(network, address string, options ...DialOption) (Conn, error) {
+	do := dialOptions{
+		dialer: &net.Dialer{
+			KeepAlive: time.Minute * 5,
+		},
+	}
+	for _, option := range options {
+		option.f(&do)
+	}
+	if do.dial == nil {
+		do.dial = do.dialer.Dial
+	}
+
+	netConn, err := do.dial(network, address)
+	if err != nil {
+		return nil, err
+	}
+
+	if do.useTLS {
+		var tlsConfig *tls.Config
+		if do.tlsConfig == nil {
+			tlsConfig = &tls.Config{InsecureSkipVerify: do.skipVerify}
+		} else {
+			tlsConfig = cloneTLSConfig(do.tlsConfig)
+		}
+		if tlsConfig.ServerName == "" {
+			host, _, err := net.SplitHostPort(address)
+			if err != nil {
+				netConn.Close()
+				return nil, err
+			}
+			tlsConfig.ServerName = host
+		}
+
+		tlsConn := tls.Client(netConn, tlsConfig)
+		if err := tlsConn.Handshake(); err != nil {
+			netConn.Close()
+			return nil, err
+		}
+		netConn = tlsConn
+	}
+
+	c := &conn{
+		conn:         netConn,
+		bw:           bufio.NewWriter(netConn),
+		br:           bufio.NewReader(netConn),
+		readTimeout:  do.readTimeout,
+		writeTimeout: do.writeTimeout,
+	}
+
+	if do.password != "" {
+		if _, err := c.Do("AUTH", do.password); err != nil {
+			netConn.Close()
+			return nil, err
+		}
+	}
+
+	if do.db != 0 {
+		if _, err := c.Do("SELECT", do.db); err != nil {
+			netConn.Close()
+			return nil, err
+		}
+	}
+
+	return c, nil
+}
+
+var pathDBRegexp = regexp.MustCompile(`/(\d*)\z`)
+
+// DialURL connects to a Redis server at the given URL using the Redis
+// URI scheme. URLs should follow the draft IANA specification for the
+// scheme (https://www.iana.org/assignments/uri-schemes/prov/redis).
+func DialURL(rawurl string, options ...DialOption) (Conn, error) {
+	u, err := url.Parse(rawurl)
+	if err != nil {
+		return nil, err
+	}
+
+	if u.Scheme != "redis" && u.Scheme != "rediss" {
+		return nil, fmt.Errorf("invalid redis URL scheme: %s", u.Scheme)
+	}
+
+	// As per the IANA draft spec, the host defaults to localhost and
+	// the port defaults to 6379.
+	host, port, err := net.SplitHostPort(u.Host)
+	if err != nil {
+		// assume port is missing
+		host = u.Host
+		port = "6379"
+	}
+	if host == "" {
+		host = "localhost"
+	}
+	address := net.JoinHostPort(host, port)
+
+	if u.User != nil {
+		password, isSet := u.User.Password()
+		if isSet {
+			options = append(options, DialPassword(password))
+		}
+	}
+
+	match := pathDBRegexp.FindStringSubmatch(u.Path)
+	if len(match) == 2 {
+		db := 0
+		if len(match[1]) > 0 {
+			db, err = strconv.Atoi(match[1])
+			if err != nil {
+				return nil, fmt.Errorf("invalid database: %s", u.Path[1:])
+			}
+		}
+		if db != 0 {
+			options = append(options, DialDatabase(db))
+		}
+	} else if u.Path != "" {
+		return nil, fmt.Errorf("invalid database: %s", u.Path[1:])
+	}
+
+	options = append(options, DialUseTLS(u.Scheme == "rediss"))
+
+	return Dial("tcp", address, options...)
+}
+
+// NewConn returns a new Redigo connection for the given net connection.
+func NewConn(netConn net.Conn, readTimeout, writeTimeout time.Duration) Conn {
+	return &conn{
+		conn:         netConn,
+		bw:           bufio.NewWriter(netConn),
+		br:           bufio.NewReader(netConn),
+		readTimeout:  readTimeout,
+		writeTimeout: writeTimeout,
+	}
+}
+
+func (c *conn) Close() error {
+	c.mu.Lock()
+	err := c.err
+	if c.err == nil {
+		c.err = errors.New("redigo: closed")
+		err = c.conn.Close()
+	}
+	c.mu.Unlock()
+	return err
+}
+
+func (c *conn) fatal(err error) error {
+	c.mu.Lock()
+	if c.err == nil {
+		c.err = err
+		// Close connection to force errors on subsequent calls and to unblock
+		// other reader or writer.
+		c.conn.Close()
+	}
+	c.mu.Unlock()
+	return err
+}
+
+func (c *conn) Err() error {
+	c.mu.Lock()
+	err := c.err
+	c.mu.Unlock()
+	return err
+}
+
+func (c *conn) writeLen(prefix byte, n int) error {
+	c.lenScratch[len(c.lenScratch)-1] = '\n'
+	c.lenScratch[len(c.lenScratch)-2] = '\r'
+	i := len(c.lenScratch) - 3
+	for {
+		c.lenScratch[i] = byte('0' + n%10)
+		i -= 1
+		n = n / 10
+		if n == 0 {
+			break
+		}
+	}
+	c.lenScratch[i] = prefix
+	_, err := c.bw.Write(c.lenScratch[i:])
+	return err
+}
+
+func (c *conn) writeString(s string) error {
+	c.writeLen('$', len(s))
+	c.bw.WriteString(s)
+	_, err := c.bw.WriteString("\r\n")
+	return err
+}
+
+func (c *conn) writeBytes(p []byte) error {
+	c.writeLen('$', len(p))
+	c.bw.Write(p)
+	_, err := c.bw.WriteString("\r\n")
+	return err
+}
+
+func (c *conn) writeInt64(n int64) error {
+	return c.writeBytes(strconv.AppendInt(c.numScratch[:0], n, 10))
+}
+
+func (c *conn) writeFloat64(n float64) error {
+	return c.writeBytes(strconv.AppendFloat(c.numScratch[:0], n, 'g', -1, 64))
+}
+
+func (c *conn) writeCommand(cmd string, args []interface{}) error {
+	c.writeLen('*', 1+len(args))
+	if err := c.writeString(cmd); err != nil {
+		return err
+	}
+	for _, arg := range args {
+		if err := c.writeArg(arg, true); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func (c *conn) writeArg(arg interface{}, argumentTypeOK bool) (err error) {
+	switch arg := arg.(type) {
+	case string:
+		return c.writeString(arg)
+	case []byte:
+		return c.writeBytes(arg)
+	case int:
+		return c.writeInt64(int64(arg))
+	case int64:
+		return c.writeInt64(arg)
+	case float64:
+		return c.writeFloat64(arg)
+	case bool:
+		if arg {
+			return c.writeString("1")
+		} else {
+			return c.writeString("0")
+		}
+	case nil:
+		return c.writeString("")
+	case Argument:
+		if argumentTypeOK {
+			return c.writeArg(arg.RedisArg(), false)
+		}
+		// See comment in default clause below.
+		var buf bytes.Buffer
+		fmt.Fprint(&buf, arg)
+		return c.writeBytes(buf.Bytes())
+	default:
+		// This default clause is intended to handle builtin numeric types.
+		// The function should return an error for other types, but this is not
+		// done for compatibility with previous versions of the package.
+		var buf bytes.Buffer
+		fmt.Fprint(&buf, arg)
+		return c.writeBytes(buf.Bytes())
+	}
+}
+
+type protocolError string
+
+func (pe protocolError) Error() string {
+	return fmt.Sprintf("redigo: %s (possible server error or unsupported concurrent read by application)", string(pe))
+}
+
+// readLine reads a line of input from the RESP stream.
+func (c *conn) readLine() ([]byte, error) {
+	// To avoid allocations, attempt to read the line using ReadSlice. This
+	// call typically succeeds. The known case where the call fails is when
+	// reading the output from the MONITOR command.
+	p, err := c.br.ReadSlice('\n')
+	if err == bufio.ErrBufferFull {
+		// The line does not fit in the bufio.Reader's buffer. Fall back to
+		// allocating a buffer for the line.
+		buf := append([]byte{}, p...)
+		for err == bufio.ErrBufferFull {
+			p, err = c.br.ReadSlice('\n')
+			buf = append(buf, p...)
+		}
+		p = buf
+	}
+	if err != nil {
+		return nil, err
+	}
+	i := len(p) - 2
+	if i < 0 || p[i] != '\r' {
+		return nil, protocolError("bad response line terminator")
+	}
+	return p[:i], nil
+}
+
+// parseLen parses bulk string and array lengths.
+func parseLen(p []byte) (int, error) {
+	if len(p) == 0 {
+		return -1, protocolError("malformed length")
+	}
+
+	if p[0] == '-' && len(p) == 2 && p[1] == '1' {
+		// handle $-1 and $-1 null replies.
+		return -1, nil
+	}
+
+	var n int
+	for _, b := range p {
+		n *= 10
+		if b < '0' || b > '9' {
+			return -1, protocolError("illegal bytes in length")
+		}
+		n += int(b - '0')
+	}
+
+	return n, nil
+}
+
+// parseInt parses an integer reply.
+func parseInt(p []byte) (interface{}, error) {
+	if len(p) == 0 {
+		return 0, protocolError("malformed integer")
+	}
+
+	var negate bool
+	if p[0] == '-' {
+		negate = true
+		p = p[1:]
+		if len(p) == 0 {
+			return 0, protocolError("malformed integer")
+		}
+	}
+
+	var n int64
+	for _, b := range p {
+		n *= 10
+		if b < '0' || b > '9' {
+			return 0, protocolError("illegal bytes in length")
+		}
+		n += int64(b - '0')
+	}
+
+	if negate {
+		n = -n
+	}
+	return n, nil
+}
+
+var (
+	okReply   interface{} = "OK"
+	pongReply interface{} = "PONG"
+)
+
+func (c *conn) readReply() (interface{}, error) {
+	line, err := c.readLine()
+	if err != nil {
+		return nil, err
+	}
+	if len(line) == 0 {
+		return nil, protocolError("short response line")
+	}
+	switch line[0] {
+	case '+':
+		switch {
+		case len(line) == 3 && line[1] == 'O' && line[2] == 'K':
+			// Avoid allocation for frequent "+OK" response.
+			return okReply, nil
+		case len(line) == 5 && line[1] == 'P' && line[2] == 'O' && line[3] == 'N' && line[4] == 'G':
+			// Avoid allocation in PING command benchmarks :)
+			return pongReply, nil
+		default:
+			return string(line[1:]), nil
+		}
+	case '-':
+		return Error(string(line[1:])), nil
+	case ':':
+		return parseInt(line[1:])
+	case '$':
+		n, err := parseLen(line[1:])
+		if n < 0 || err != nil {
+			return nil, err
+		}
+		p := make([]byte, n)
+		_, err = io.ReadFull(c.br, p)
+		if err != nil {
+			return nil, err
+		}
+		if line, err := c.readLine(); err != nil {
+			return nil, err
+		} else if len(line) != 0 {
+			return nil, protocolError("bad bulk string format")
+		}
+		return p, nil
+	case '*':
+		n, err := parseLen(line[1:])
+		if n < 0 || err != nil {
+			return nil, err
+		}
+		r := make([]interface{}, n)
+		for i := range r {
+			r[i], err = c.readReply()
+			if err != nil {
+				return nil, err
+			}
+		}
+		return r, nil
+	}
+	return nil, protocolError("unexpected response line")
+}
+
+func (c *conn) Send(cmd string, args ...interface{}) error {
+	c.mu.Lock()
+	c.pending += 1
+	c.mu.Unlock()
+	if c.writeTimeout != 0 {
+		c.conn.SetWriteDeadline(time.Now().Add(c.writeTimeout))
+	}
+	if err := c.writeCommand(cmd, args); err != nil {
+		return c.fatal(err)
+	}
+	return nil
+}
+
+func (c *conn) Flush() error {
+	if c.writeTimeout != 0 {
+		c.conn.SetWriteDeadline(time.Now().Add(c.writeTimeout))
+	}
+	if err := c.bw.Flush(); err != nil {
+		return c.fatal(err)
+	}
+	return nil
+}
+
+func (c *conn) Receive() (interface{}, error) {
+	return c.ReceiveWithTimeout(c.readTimeout)
+}
+
+func (c *conn) ReceiveWithTimeout(timeout time.Duration) (reply interface{}, err error) {
+	var deadline time.Time
+	if timeout != 0 {
+		deadline = time.Now().Add(timeout)
+	}
+	c.conn.SetReadDeadline(deadline)
+
+	if reply, err = c.readReply(); err != nil {
+		return nil, c.fatal(err)
+	}
+	// When using pub/sub, the number of receives can be greater than the
+	// number of sends. To enable normal use of the connection after
+	// unsubscribing from all channels, we do not decrement pending to a
+	// negative value.
+	//
+	// The pending field is decremented after the reply is read to handle the
+	// case where Receive is called before Send.
+	c.mu.Lock()
+	if c.pending > 0 {
+		c.pending -= 1
+	}
+	c.mu.Unlock()
+	if err, ok := reply.(Error); ok {
+		return nil, err
+	}
+	return
+}
+
+func (c *conn) Do(cmd string, args ...interface{}) (interface{}, error) {
+	return c.DoWithTimeout(c.readTimeout, cmd, args...)
+}
+
+func (c *conn) DoWithTimeout(readTimeout time.Duration, cmd string, args ...interface{}) (interface{}, error) {
+	c.mu.Lock()
+	pending := c.pending
+	c.pending = 0
+	c.mu.Unlock()
+
+	if cmd == "" && pending == 0 {
+		return nil, nil
+	}
+
+	if c.writeTimeout != 0 {
+		c.conn.SetWriteDeadline(time.Now().Add(c.writeTimeout))
+	}
+
+	if cmd != "" {
+		if err := c.writeCommand(cmd, args); err != nil {
+			return nil, c.fatal(err)
+		}
+	}
+
+	if err := c.bw.Flush(); err != nil {
+		return nil, c.fatal(err)
+	}
+
+	var deadline time.Time
+	if readTimeout != 0 {
+		deadline = time.Now().Add(readTimeout)
+	}
+	c.conn.SetReadDeadline(deadline)
+
+	if cmd == "" {
+		reply := make([]interface{}, pending)
+		for i := range reply {
+			r, e := c.readReply()
+			if e != nil {
+				return nil, c.fatal(e)
+			}
+			reply[i] = r
+		}
+		return reply, nil
+	}
+
+	var err error
+	var reply interface{}
+	for i := 0; i <= pending; i++ {
+		var e error
+		if reply, e = c.readReply(); e != nil {
+			return nil, c.fatal(e)
+		}
+		if e, ok := reply.(Error); ok && err == nil {
+			err = e
+		}
+	}
+	return reply, err
+}

+ 177 - 0
vendor/github.com/gomodule/redigo/redis/doc.go

@@ -0,0 +1,177 @@
+// Copyright 2012 Gary Burd
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+// Package redis is a client for the Redis database.
+//
+// The Redigo FAQ (https://github.com/gomodule/redigo/wiki/FAQ) contains more
+// documentation about this package.
+//
+// Connections
+//
+// The Conn interface is the primary interface for working with Redis.
+// Applications create connections by calling the Dial, DialWithTimeout or
+// NewConn functions. In the future, functions will be added for creating
+// sharded and other types of connections.
+//
+// The application must call the connection Close method when the application
+// is done with the connection.
+//
+// Executing Commands
+//
+// The Conn interface has a generic method for executing Redis commands:
+//
+//  Do(commandName string, args ...interface{}) (reply interface{}, err error)
+//
+// The Redis command reference (http://redis.io/commands) lists the available
+// commands. An example of using the Redis APPEND command is:
+//
+//  n, err := conn.Do("APPEND", "key", "value")
+//
+// The Do method converts command arguments to bulk strings for transmission
+// to the server as follows:
+//
+//  Go Type                 Conversion
+//  []byte                  Sent as is
+//  string                  Sent as is
+//  int, int64              strconv.FormatInt(v)
+//  float64                 strconv.FormatFloat(v, 'g', -1, 64)
+//  bool                    true -> "1", false -> "0"
+//  nil                     ""
+//  all other types         fmt.Fprint(w, v)
+//
+// Redis command reply types are represented using the following Go types:
+//
+//  Redis type              Go type
+//  error                   redis.Error
+//  integer                 int64
+//  simple string           string
+//  bulk string             []byte or nil if value not present.
+//  array                   []interface{} or nil if value not present.
+//
+// Use type assertions or the reply helper functions to convert from
+// interface{} to the specific Go type for the command result.
+//
+// Pipelining
+//
+// Connections support pipelining using the Send, Flush and Receive methods.
+//
+//  Send(commandName string, args ...interface{}) error
+//  Flush() error
+//  Receive() (reply interface{}, err error)
+//
+// Send writes the command to the connection's output buffer. Flush flushes the
+// connection's output buffer to the server. Receive reads a single reply from
+// the server. The following example shows a simple pipeline.
+//
+//  c.Send("SET", "foo", "bar")
+//  c.Send("GET", "foo")
+//  c.Flush()
+//  c.Receive() // reply from SET
+//  v, err = c.Receive() // reply from GET
+//
+// The Do method combines the functionality of the Send, Flush and Receive
+// methods. The Do method starts by writing the command and flushing the output
+// buffer. Next, the Do method receives all pending replies including the reply
+// for the command just sent by Do. If any of the received replies is an error,
+// then Do returns the error. If there are no errors, then Do returns the last
+// reply. If the command argument to the Do method is "", then the Do method
+// will flush the output buffer and receive pending replies without sending a
+// command.
+//
+// Use the Send and Do methods to implement pipelined transactions.
+//
+//  c.Send("MULTI")
+//  c.Send("INCR", "foo")
+//  c.Send("INCR", "bar")
+//  r, err := c.Do("EXEC")
+//  fmt.Println(r) // prints [1, 1]
+//
+// Concurrency
+//
+// Connections support one concurrent caller to the Receive method and one
+// concurrent caller to the Send and Flush methods. No other concurrency is
+// supported including concurrent calls to the Do method.
+//
+// For full concurrent access to Redis, use the thread-safe Pool to get, use
+// and release a connection from within a goroutine. Connections returned from
+// a Pool have the concurrency restrictions described in the previous
+// paragraph.
+//
+// Publish and Subscribe
+//
+// Use the Send, Flush and Receive methods to implement Pub/Sub subscribers.
+//
+//  c.Send("SUBSCRIBE", "example")
+//  c.Flush()
+//  for {
+//      reply, err := c.Receive()
+//      if err != nil {
+//          return err
+//      }
+//      // process pushed message
+//  }
+//
+// The PubSubConn type wraps a Conn with convenience methods for implementing
+// subscribers. The Subscribe, PSubscribe, Unsubscribe and PUnsubscribe methods
+// send and flush a subscription management command. The receive method
+// converts a pushed message to convenient types for use in a type switch.
+//
+//  psc := redis.PubSubConn{Conn: c}
+//  psc.Subscribe("example")
+//  for {
+//      switch v := psc.Receive().(type) {
+//      case redis.Message:
+//          fmt.Printf("%s: message: %s\n", v.Channel, v.Data)
+//      case redis.Subscription:
+//          fmt.Printf("%s: %s %d\n", v.Channel, v.Kind, v.Count)
+//      case error:
+//          return v
+//      }
+//  }
+//
+// Reply Helpers
+//
+// The Bool, Int, Bytes, String, Strings and Values functions convert a reply
+// to a value of a specific type. To allow convenient wrapping of calls to the
+// connection Do and Receive methods, the functions take a second argument of
+// type error.  If the error is non-nil, then the helper function returns the
+// error. If the error is nil, the function converts the reply to the specified
+// type:
+//
+//  exists, err := redis.Bool(c.Do("EXISTS", "foo"))
+//  if err != nil {
+//      // handle error return from c.Do or type conversion error.
+//  }
+//
+// The Scan function converts elements of a array reply to Go types:
+//
+//  var value1 int
+//  var value2 string
+//  reply, err := redis.Values(c.Do("MGET", "key1", "key2"))
+//  if err != nil {
+//      // handle error
+//  }
+//   if _, err := redis.Scan(reply, &value1, &value2); err != nil {
+//      // handle error
+//  }
+//
+// Errors
+//
+// Connection methods return error replies from the server as type redis.Error.
+//
+// Call the connection Err() method to determine if the connection encountered
+// non-recoverable error such as a network error or protocol parsing error. If
+// Err() returns a non-nil value, then the connection is not usable and should
+// be closed.
+package redis

+ 27 - 0
vendor/github.com/gomodule/redigo/redis/go16.go

@@ -0,0 +1,27 @@
+// +build !go1.7
+
+package redis
+
+import "crypto/tls"
+
+func cloneTLSConfig(cfg *tls.Config) *tls.Config {
+	return &tls.Config{
+		Rand:                     cfg.Rand,
+		Time:                     cfg.Time,
+		Certificates:             cfg.Certificates,
+		NameToCertificate:        cfg.NameToCertificate,
+		GetCertificate:           cfg.GetCertificate,
+		RootCAs:                  cfg.RootCAs,
+		NextProtos:               cfg.NextProtos,
+		ServerName:               cfg.ServerName,
+		ClientAuth:               cfg.ClientAuth,
+		ClientCAs:                cfg.ClientCAs,
+		InsecureSkipVerify:       cfg.InsecureSkipVerify,
+		CipherSuites:             cfg.CipherSuites,
+		PreferServerCipherSuites: cfg.PreferServerCipherSuites,
+		ClientSessionCache:       cfg.ClientSessionCache,
+		MinVersion:               cfg.MinVersion,
+		MaxVersion:               cfg.MaxVersion,
+		CurvePreferences:         cfg.CurvePreferences,
+	}
+}

+ 29 - 0
vendor/github.com/gomodule/redigo/redis/go17.go

@@ -0,0 +1,29 @@
+// +build go1.7,!go1.8
+
+package redis
+
+import "crypto/tls"
+
+func cloneTLSConfig(cfg *tls.Config) *tls.Config {
+	return &tls.Config{
+		Rand:                        cfg.Rand,
+		Time:                        cfg.Time,
+		Certificates:                cfg.Certificates,
+		NameToCertificate:           cfg.NameToCertificate,
+		GetCertificate:              cfg.GetCertificate,
+		RootCAs:                     cfg.RootCAs,
+		NextProtos:                  cfg.NextProtos,
+		ServerName:                  cfg.ServerName,
+		ClientAuth:                  cfg.ClientAuth,
+		ClientCAs:                   cfg.ClientCAs,
+		InsecureSkipVerify:          cfg.InsecureSkipVerify,
+		CipherSuites:                cfg.CipherSuites,
+		PreferServerCipherSuites:    cfg.PreferServerCipherSuites,
+		ClientSessionCache:          cfg.ClientSessionCache,
+		MinVersion:                  cfg.MinVersion,
+		MaxVersion:                  cfg.MaxVersion,
+		CurvePreferences:            cfg.CurvePreferences,
+		DynamicRecordSizingDisabled: cfg.DynamicRecordSizingDisabled,
+		Renegotiation:               cfg.Renegotiation,
+	}
+}

+ 9 - 0
vendor/github.com/gomodule/redigo/redis/go18.go

@@ -0,0 +1,9 @@
+// +build go1.8
+
+package redis
+
+import "crypto/tls"
+
+func cloneTLSConfig(cfg *tls.Config) *tls.Config {
+	return cfg.Clone()
+}

+ 146 - 0
vendor/github.com/gomodule/redigo/redis/log.go

@@ -0,0 +1,146 @@
+// Copyright 2012 Gary Burd
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package redis
+
+import (
+	"bytes"
+	"fmt"
+	"log"
+	"time"
+)
+
+var (
+	_ ConnWithTimeout = (*loggingConn)(nil)
+)
+
+// NewLoggingConn returns a logging wrapper around a connection.
+func NewLoggingConn(conn Conn, logger *log.Logger, prefix string) Conn {
+	if prefix != "" {
+		prefix = prefix + "."
+	}
+	return &loggingConn{conn, logger, prefix, nil}
+}
+
+//NewLoggingConnFilter returns a logging wrapper around a connection and a filter function.
+func NewLoggingConnFilter(conn Conn, logger *log.Logger, prefix string, skip func(cmdName string) bool) Conn {
+	if prefix != "" {
+		prefix = prefix + "."
+	}
+	return &loggingConn{conn, logger, prefix, skip}
+}
+
+type loggingConn struct {
+	Conn
+	logger *log.Logger
+	prefix string
+	skip   func(cmdName string) bool
+}
+
+func (c *loggingConn) Close() error {
+	err := c.Conn.Close()
+	var buf bytes.Buffer
+	fmt.Fprintf(&buf, "%sClose() -> (%v)", c.prefix, err)
+	c.logger.Output(2, buf.String())
+	return err
+}
+
+func (c *loggingConn) printValue(buf *bytes.Buffer, v interface{}) {
+	const chop = 32
+	switch v := v.(type) {
+	case []byte:
+		if len(v) > chop {
+			fmt.Fprintf(buf, "%q...", v[:chop])
+		} else {
+			fmt.Fprintf(buf, "%q", v)
+		}
+	case string:
+		if len(v) > chop {
+			fmt.Fprintf(buf, "%q...", v[:chop])
+		} else {
+			fmt.Fprintf(buf, "%q", v)
+		}
+	case []interface{}:
+		if len(v) == 0 {
+			buf.WriteString("[]")
+		} else {
+			sep := "["
+			fin := "]"
+			if len(v) > chop {
+				v = v[:chop]
+				fin = "...]"
+			}
+			for _, vv := range v {
+				buf.WriteString(sep)
+				c.printValue(buf, vv)
+				sep = ", "
+			}
+			buf.WriteString(fin)
+		}
+	default:
+		fmt.Fprint(buf, v)
+	}
+}
+
+func (c *loggingConn) print(method, commandName string, args []interface{}, reply interface{}, err error) {
+	if c.skip != nil && c.skip(commandName) {
+		return
+	}
+	var buf bytes.Buffer
+	fmt.Fprintf(&buf, "%s%s(", c.prefix, method)
+	if method != "Receive" {
+		buf.WriteString(commandName)
+		for _, arg := range args {
+			buf.WriteString(", ")
+			c.printValue(&buf, arg)
+		}
+	}
+	buf.WriteString(") -> (")
+	if method != "Send" {
+		c.printValue(&buf, reply)
+		buf.WriteString(", ")
+	}
+	fmt.Fprintf(&buf, "%v)", err)
+	c.logger.Output(3, buf.String())
+}
+
+func (c *loggingConn) Do(commandName string, args ...interface{}) (interface{}, error) {
+	reply, err := c.Conn.Do(commandName, args...)
+	c.print("Do", commandName, args, reply, err)
+	return reply, err
+}
+
+func (c *loggingConn) DoWithTimeout(timeout time.Duration, commandName string, args ...interface{}) (interface{}, error) {
+	reply, err := DoWithTimeout(c.Conn, timeout, commandName, args...)
+	c.print("DoWithTimeout", commandName, args, reply, err)
+	return reply, err
+}
+
+func (c *loggingConn) Send(commandName string, args ...interface{}) error {
+	err := c.Conn.Send(commandName, args...)
+	c.print("Send", commandName, args, nil, err)
+	return err
+}
+
+func (c *loggingConn) Receive() (interface{}, error) {
+	reply, err := c.Conn.Receive()
+	c.print("Receive", "", nil, reply, err)
+	return reply, err
+}
+
+func (c *loggingConn) ReceiveWithTimeout(timeout time.Duration) (interface{}, error) {
+	reply, err := ReceiveWithTimeout(c.Conn, timeout)
+	c.print("ReceiveWithTimeout", "", nil, reply, err)
+	return reply, err
+}

+ 560 - 0
vendor/github.com/gomodule/redigo/redis/pool.go

@@ -0,0 +1,560 @@
+// Copyright 2012 Gary Burd
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package redis
+
+import (
+	"bytes"
+	"crypto/rand"
+	"crypto/sha1"
+	"errors"
+	"io"
+	"strconv"
+	"sync"
+	"sync/atomic"
+	"time"
+)
+
+var (
+	_ ConnWithTimeout = (*activeConn)(nil)
+	_ ConnWithTimeout = (*errorConn)(nil)
+)
+
+var nowFunc = time.Now // for testing
+
+// ErrPoolExhausted is returned from a pool connection method (Do, Send,
+// Receive, Flush, Err) when the maximum number of database connections in the
+// pool has been reached.
+var ErrPoolExhausted = errors.New("redigo: connection pool exhausted")
+
+var (
+	errPoolClosed = errors.New("redigo: connection pool closed")
+	errConnClosed = errors.New("redigo: connection closed")
+)
+
+// Pool maintains a pool of connections. The application calls the Get method
+// to get a connection from the pool and the connection's Close method to
+// return the connection's resources to the pool.
+//
+// The following example shows how to use a pool in a web application. The
+// application creates a pool at application startup and makes it available to
+// request handlers using a package level variable. The pool configuration used
+// here is an example, not a recommendation.
+//
+//  func newPool(addr string) *redis.Pool {
+//    return &redis.Pool{
+//      MaxIdle: 3,
+//      IdleTimeout: 240 * time.Second,
+//      Dial: func () (redis.Conn, error) { return redis.Dial("tcp", addr) },
+//    }
+//  }
+//
+//  var (
+//    pool *redis.Pool
+//    redisServer = flag.String("redisServer", ":6379", "")
+//  )
+//
+//  func main() {
+//    flag.Parse()
+//    pool = newPool(*redisServer)
+//    ...
+//  }
+//
+// A request handler gets a connection from the pool and closes the connection
+// when the handler is done:
+//
+//  func serveHome(w http.ResponseWriter, r *http.Request) {
+//      conn := pool.Get()
+//      defer conn.Close()
+//      ...
+//  }
+//
+// Use the Dial function to authenticate connections with the AUTH command or
+// select a database with the SELECT command:
+//
+//  pool := &redis.Pool{
+//    // Other pool configuration not shown in this example.
+//    Dial: func () (redis.Conn, error) {
+//      c, err := redis.Dial("tcp", server)
+//      if err != nil {
+//        return nil, err
+//      }
+//      if _, err := c.Do("AUTH", password); err != nil {
+//        c.Close()
+//        return nil, err
+//      }
+//      if _, err := c.Do("SELECT", db); err != nil {
+//        c.Close()
+//        return nil, err
+//      }
+//      return c, nil
+//    },
+//  }
+//
+// Use the TestOnBorrow function to check the health of an idle connection
+// before the connection is returned to the application. This example PINGs
+// connections that have been idle more than a minute:
+//
+//  pool := &redis.Pool{
+//    // Other pool configuration not shown in this example.
+//    TestOnBorrow: func(c redis.Conn, t time.Time) error {
+//      if time.Since(t) < time.Minute {
+//        return nil
+//      }
+//      _, err := c.Do("PING")
+//      return err
+//    },
+//  }
+//
+type Pool struct {
+	// Dial is an application supplied function for creating and configuring a
+	// connection.
+	//
+	// The connection returned from Dial must not be in a special state
+	// (subscribed to pubsub channel, transaction started, ...).
+	Dial func() (Conn, error)
+
+	// TestOnBorrow is an optional application supplied function for checking
+	// the health of an idle connection before the connection is used again by
+	// the application. Argument t is the time that the connection was returned
+	// to the pool. If the function returns an error, then the connection is
+	// closed.
+	TestOnBorrow func(c Conn, t time.Time) error
+
+	// Maximum number of idle connections in the pool.
+	MaxIdle int
+
+	// Maximum number of connections allocated by the pool at a given time.
+	// When zero, there is no limit on the number of connections in the pool.
+	MaxActive int
+
+	// Close connections after remaining idle for this duration. If the value
+	// is zero, then idle connections are not closed. Applications should set
+	// the timeout to a value less than the server's timeout.
+	IdleTimeout time.Duration
+
+	// If Wait is true and the pool is at the MaxActive limit, then Get() waits
+	// for a connection to be returned to the pool before returning.
+	Wait bool
+
+	// Close connections older than this duration. If the value is zero, then
+	// the pool does not close connections based on age.
+	MaxConnLifetime time.Duration
+
+	chInitialized uint32 // set to 1 when field ch is initialized
+
+	mu     sync.Mutex    // mu protects the following fields
+	closed bool          // set to true when the pool is closed.
+	active int           // the number of open connections in the pool
+	ch     chan struct{} // limits open connections when p.Wait is true
+	idle   idleList      // idle connections
+}
+
+// NewPool creates a new pool.
+//
+// Deprecated: Initialize the Pool directory as shown in the example.
+func NewPool(newFn func() (Conn, error), maxIdle int) *Pool {
+	return &Pool{Dial: newFn, MaxIdle: maxIdle}
+}
+
+// Get gets a connection. The application must close the returned connection.
+// This method always returns a valid connection so that applications can defer
+// error handling to the first use of the connection. If there is an error
+// getting an underlying connection, then the connection Err, Do, Send, Flush
+// and Receive methods return that error.
+func (p *Pool) Get() Conn {
+	pc, err := p.get(nil)
+	if err != nil {
+		return errorConn{err}
+	}
+	return &activeConn{p: p, pc: pc}
+}
+
+// PoolStats contains pool statistics.
+type PoolStats struct {
+	// ActiveCount is the number of connections in the pool. The count includes
+	// idle connections and connections in use.
+	ActiveCount int
+	// IdleCount is the number of idle connections in the pool.
+	IdleCount int
+}
+
+// Stats returns pool's statistics.
+func (p *Pool) Stats() PoolStats {
+	p.mu.Lock()
+	stats := PoolStats{
+		ActiveCount: p.active,
+		IdleCount:   p.idle.count,
+	}
+	p.mu.Unlock()
+
+	return stats
+}
+
+// ActiveCount returns the number of connections in the pool. The count
+// includes idle connections and connections in use.
+func (p *Pool) ActiveCount() int {
+	p.mu.Lock()
+	active := p.active
+	p.mu.Unlock()
+	return active
+}
+
+// IdleCount returns the number of idle connections in the pool.
+func (p *Pool) IdleCount() int {
+	p.mu.Lock()
+	idle := p.idle.count
+	p.mu.Unlock()
+	return idle
+}
+
+// Close releases the resources used by the pool.
+func (p *Pool) Close() error {
+	p.mu.Lock()
+	if p.closed {
+		p.mu.Unlock()
+		return nil
+	}
+	p.closed = true
+	p.active -= p.idle.count
+	pc := p.idle.front
+	p.idle.count = 0
+	p.idle.front, p.idle.back = nil, nil
+	if p.ch != nil {
+		close(p.ch)
+	}
+	p.mu.Unlock()
+	for ; pc != nil; pc = pc.next {
+		pc.c.Close()
+	}
+	return nil
+}
+
+func (p *Pool) lazyInit() {
+	// Fast path.
+	if atomic.LoadUint32(&p.chInitialized) == 1 {
+		return
+	}
+	// Slow path.
+	p.mu.Lock()
+	if p.chInitialized == 0 {
+		p.ch = make(chan struct{}, p.MaxActive)
+		if p.closed {
+			close(p.ch)
+		} else {
+			for i := 0; i < p.MaxActive; i++ {
+				p.ch <- struct{}{}
+			}
+		}
+		atomic.StoreUint32(&p.chInitialized, 1)
+	}
+	p.mu.Unlock()
+}
+
+// get prunes stale connections and returns a connection from the idle list or
+// creates a new connection.
+func (p *Pool) get(ctx interface {
+	Done() <-chan struct{}
+	Err() error
+}) (*poolConn, error) {
+
+	// Handle limit for p.Wait == true.
+	if p.Wait && p.MaxActive > 0 {
+		p.lazyInit()
+		if ctx == nil {
+			<-p.ch
+		} else {
+			select {
+			case <-p.ch:
+			case <-ctx.Done():
+				return nil, ctx.Err()
+			}
+		}
+	}
+
+	p.mu.Lock()
+
+	// Prune stale connections at the back of the idle list.
+	if p.IdleTimeout > 0 {
+		n := p.idle.count
+		for i := 0; i < n && p.idle.back != nil && p.idle.back.t.Add(p.IdleTimeout).Before(nowFunc()); i++ {
+			pc := p.idle.back
+			p.idle.popBack()
+			p.mu.Unlock()
+			pc.c.Close()
+			p.mu.Lock()
+			p.active--
+		}
+	}
+
+	// Get idle connection from the front of idle list.
+	for p.idle.front != nil {
+		pc := p.idle.front
+		p.idle.popFront()
+		p.mu.Unlock()
+		if (p.TestOnBorrow == nil || p.TestOnBorrow(pc.c, pc.t) == nil) &&
+			(p.MaxConnLifetime == 0 || nowFunc().Sub(pc.created) < p.MaxConnLifetime) {
+			return pc, nil
+		}
+		pc.c.Close()
+		p.mu.Lock()
+		p.active--
+	}
+
+	// Check for pool closed before dialing a new connection.
+	if p.closed {
+		p.mu.Unlock()
+		return nil, errors.New("redigo: get on closed pool")
+	}
+
+	// Handle limit for p.Wait == false.
+	if !p.Wait && p.MaxActive > 0 && p.active >= p.MaxActive {
+		p.mu.Unlock()
+		return nil, ErrPoolExhausted
+	}
+
+	p.active++
+	p.mu.Unlock()
+	c, err := p.Dial()
+	if err != nil {
+		c = nil
+		p.mu.Lock()
+		p.active--
+		if p.ch != nil && !p.closed {
+			p.ch <- struct{}{}
+		}
+		p.mu.Unlock()
+	}
+	return &poolConn{c: c, created: nowFunc()}, err
+}
+
+func (p *Pool) put(pc *poolConn, forceClose bool) error {
+	p.mu.Lock()
+	if !p.closed && !forceClose {
+		pc.t = nowFunc()
+		p.idle.pushFront(pc)
+		if p.idle.count > p.MaxIdle {
+			pc = p.idle.back
+			p.idle.popBack()
+		} else {
+			pc = nil
+		}
+	}
+
+	if pc != nil {
+		p.mu.Unlock()
+		pc.c.Close()
+		p.mu.Lock()
+		p.active--
+	}
+
+	if p.ch != nil && !p.closed {
+		p.ch <- struct{}{}
+	}
+	p.mu.Unlock()
+	return nil
+}
+
+type activeConn struct {
+	p     *Pool
+	pc    *poolConn
+	state int
+}
+
+var (
+	sentinel     []byte
+	sentinelOnce sync.Once
+)
+
+func initSentinel() {
+	p := make([]byte, 64)
+	if _, err := rand.Read(p); err == nil {
+		sentinel = p
+	} else {
+		h := sha1.New()
+		io.WriteString(h, "Oops, rand failed. Use time instead.")
+		io.WriteString(h, strconv.FormatInt(time.Now().UnixNano(), 10))
+		sentinel = h.Sum(nil)
+	}
+}
+
+func (ac *activeConn) Close() error {
+	pc := ac.pc
+	if pc == nil {
+		return nil
+	}
+	ac.pc = nil
+
+	if ac.state&connectionMultiState != 0 {
+		pc.c.Send("DISCARD")
+		ac.state &^= (connectionMultiState | connectionWatchState)
+	} else if ac.state&connectionWatchState != 0 {
+		pc.c.Send("UNWATCH")
+		ac.state &^= connectionWatchState
+	}
+	if ac.state&connectionSubscribeState != 0 {
+		pc.c.Send("UNSUBSCRIBE")
+		pc.c.Send("PUNSUBSCRIBE")
+		// To detect the end of the message stream, ask the server to echo
+		// a sentinel value and read until we see that value.
+		sentinelOnce.Do(initSentinel)
+		pc.c.Send("ECHO", sentinel)
+		pc.c.Flush()
+		for {
+			p, err := pc.c.Receive()
+			if err != nil {
+				break
+			}
+			if p, ok := p.([]byte); ok && bytes.Equal(p, sentinel) {
+				ac.state &^= connectionSubscribeState
+				break
+			}
+		}
+	}
+	pc.c.Do("")
+	ac.p.put(pc, ac.state != 0 || pc.c.Err() != nil)
+	return nil
+}
+
+func (ac *activeConn) Err() error {
+	pc := ac.pc
+	if pc == nil {
+		return errConnClosed
+	}
+	return pc.c.Err()
+}
+
+func (ac *activeConn) Do(commandName string, args ...interface{}) (reply interface{}, err error) {
+	pc := ac.pc
+	if pc == nil {
+		return nil, errConnClosed
+	}
+	ci := lookupCommandInfo(commandName)
+	ac.state = (ac.state | ci.Set) &^ ci.Clear
+	return pc.c.Do(commandName, args...)
+}
+
+func (ac *activeConn) DoWithTimeout(timeout time.Duration, commandName string, args ...interface{}) (reply interface{}, err error) {
+	pc := ac.pc
+	if pc == nil {
+		return nil, errConnClosed
+	}
+	cwt, ok := pc.c.(ConnWithTimeout)
+	if !ok {
+		return nil, errTimeoutNotSupported
+	}
+	ci := lookupCommandInfo(commandName)
+	ac.state = (ac.state | ci.Set) &^ ci.Clear
+	return cwt.DoWithTimeout(timeout, commandName, args...)
+}
+
+func (ac *activeConn) Send(commandName string, args ...interface{}) error {
+	pc := ac.pc
+	if pc == nil {
+		return errConnClosed
+	}
+	ci := lookupCommandInfo(commandName)
+	ac.state = (ac.state | ci.Set) &^ ci.Clear
+	return pc.c.Send(commandName, args...)
+}
+
+func (ac *activeConn) Flush() error {
+	pc := ac.pc
+	if pc == nil {
+		return errConnClosed
+	}
+	return pc.c.Flush()
+}
+
+func (ac *activeConn) Receive() (reply interface{}, err error) {
+	pc := ac.pc
+	if pc == nil {
+		return nil, errConnClosed
+	}
+	return pc.c.Receive()
+}
+
+func (ac *activeConn) ReceiveWithTimeout(timeout time.Duration) (reply interface{}, err error) {
+	pc := ac.pc
+	if pc == nil {
+		return nil, errConnClosed
+	}
+	cwt, ok := pc.c.(ConnWithTimeout)
+	if !ok {
+		return nil, errTimeoutNotSupported
+	}
+	return cwt.ReceiveWithTimeout(timeout)
+}
+
+type errorConn struct{ err error }
+
+func (ec errorConn) Do(string, ...interface{}) (interface{}, error) { return nil, ec.err }
+func (ec errorConn) DoWithTimeout(time.Duration, string, ...interface{}) (interface{}, error) {
+	return nil, ec.err
+}
+func (ec errorConn) Send(string, ...interface{}) error                     { return ec.err }
+func (ec errorConn) Err() error                                            { return ec.err }
+func (ec errorConn) Close() error                                          { return nil }
+func (ec errorConn) Flush() error                                          { return ec.err }
+func (ec errorConn) Receive() (interface{}, error)                         { return nil, ec.err }
+func (ec errorConn) ReceiveWithTimeout(time.Duration) (interface{}, error) { return nil, ec.err }
+
+type idleList struct {
+	count       int
+	front, back *poolConn
+}
+
+type poolConn struct {
+	c          Conn
+	t          time.Time
+	created    time.Time
+	next, prev *poolConn
+}
+
+func (l *idleList) pushFront(pc *poolConn) {
+	pc.next = l.front
+	pc.prev = nil
+	if l.count == 0 {
+		l.back = pc
+	} else {
+		l.front.prev = pc
+	}
+	l.front = pc
+	l.count++
+	return
+}
+
+func (l *idleList) popFront() {
+	pc := l.front
+	l.count--
+	if l.count == 0 {
+		l.front, l.back = nil, nil
+	} else {
+		pc.next.prev = nil
+		l.front = pc.next
+	}
+	pc.next, pc.prev = nil, nil
+}
+
+func (l *idleList) popBack() {
+	pc := l.back
+	l.count--
+	if l.count == 0 {
+		l.front, l.back = nil, nil
+	} else {
+		pc.prev.next = nil
+		l.back = pc.prev
+	}
+	pc.next, pc.prev = nil, nil
+}

+ 35 - 0
vendor/github.com/gomodule/redigo/redis/pool17.go

@@ -0,0 +1,35 @@
+// Copyright 2018 Gary Burd
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+// +build go1.7
+
+package redis
+
+import "context"
+
+// GetContext gets a connection using the provided context.
+//
+// The provided Context must be non-nil. If the context expires before the
+// connection is complete, an error is returned. Any expiration on the context
+// will not affect the returned connection.
+//
+// If the function completes without error, then the application must close the
+// returned connection.
+func (p *Pool) GetContext(ctx context.Context) (Conn, error) {
+	pc, err := p.get(ctx)
+	if err != nil {
+		return errorConn{err}, err
+	}
+	return &activeConn{p: p, pc: pc}, nil
+}

+ 148 - 0
vendor/github.com/gomodule/redigo/redis/pubsub.go

@@ -0,0 +1,148 @@
+// Copyright 2012 Gary Burd
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package redis
+
+import (
+	"errors"
+	"time"
+)
+
+// Subscription represents a subscribe or unsubscribe notification.
+type Subscription struct {
+	// Kind is "subscribe", "unsubscribe", "psubscribe" or "punsubscribe"
+	Kind string
+
+	// The channel that was changed.
+	Channel string
+
+	// The current number of subscriptions for connection.
+	Count int
+}
+
+// Message represents a message notification.
+type Message struct {
+	// The originating channel.
+	Channel string
+
+	// The matched pattern, if any
+	Pattern string
+
+	// The message data.
+	Data []byte
+}
+
+// Pong represents a pubsub pong notification.
+type Pong struct {
+	Data string
+}
+
+// PubSubConn wraps a Conn with convenience methods for subscribers.
+type PubSubConn struct {
+	Conn Conn
+}
+
+// Close closes the connection.
+func (c PubSubConn) Close() error {
+	return c.Conn.Close()
+}
+
+// Subscribe subscribes the connection to the specified channels.
+func (c PubSubConn) Subscribe(channel ...interface{}) error {
+	c.Conn.Send("SUBSCRIBE", channel...)
+	return c.Conn.Flush()
+}
+
+// PSubscribe subscribes the connection to the given patterns.
+func (c PubSubConn) PSubscribe(channel ...interface{}) error {
+	c.Conn.Send("PSUBSCRIBE", channel...)
+	return c.Conn.Flush()
+}
+
+// Unsubscribe unsubscribes the connection from the given channels, or from all
+// of them if none is given.
+func (c PubSubConn) Unsubscribe(channel ...interface{}) error {
+	c.Conn.Send("UNSUBSCRIBE", channel...)
+	return c.Conn.Flush()
+}
+
+// PUnsubscribe unsubscribes the connection from the given patterns, or from all
+// of them if none is given.
+func (c PubSubConn) PUnsubscribe(channel ...interface{}) error {
+	c.Conn.Send("PUNSUBSCRIBE", channel...)
+	return c.Conn.Flush()
+}
+
+// Ping sends a PING to the server with the specified data.
+//
+// The connection must be subscribed to at least one channel or pattern when
+// calling this method.
+func (c PubSubConn) Ping(data string) error {
+	c.Conn.Send("PING", data)
+	return c.Conn.Flush()
+}
+
+// Receive returns a pushed message as a Subscription, Message, Pong or error.
+// The return value is intended to be used directly in a type switch as
+// illustrated in the PubSubConn example.
+func (c PubSubConn) Receive() interface{} {
+	return c.receiveInternal(c.Conn.Receive())
+}
+
+// ReceiveWithTimeout is like Receive, but it allows the application to
+// override the connection's default timeout.
+func (c PubSubConn) ReceiveWithTimeout(timeout time.Duration) interface{} {
+	return c.receiveInternal(ReceiveWithTimeout(c.Conn, timeout))
+}
+
+func (c PubSubConn) receiveInternal(replyArg interface{}, errArg error) interface{} {
+	reply, err := Values(replyArg, errArg)
+	if err != nil {
+		return err
+	}
+
+	var kind string
+	reply, err = Scan(reply, &kind)
+	if err != nil {
+		return err
+	}
+
+	switch kind {
+	case "message":
+		var m Message
+		if _, err := Scan(reply, &m.Channel, &m.Data); err != nil {
+			return err
+		}
+		return m
+	case "pmessage":
+		var m Message
+		if _, err := Scan(reply, &m.Pattern, &m.Channel, &m.Data); err != nil {
+			return err
+		}
+		return m
+	case "subscribe", "psubscribe", "unsubscribe", "punsubscribe":
+		s := Subscription{Kind: kind}
+		if _, err := Scan(reply, &s.Channel, &s.Count); err != nil {
+			return err
+		}
+		return s
+	case "pong":
+		var p Pong
+		if _, err := Scan(reply, &p.Data); err != nil {
+			return err
+		}
+		return p
+	}
+	return errors.New("redigo: unknown pubsub notification")
+}

+ 117 - 0
vendor/github.com/gomodule/redigo/redis/redis.go

@@ -0,0 +1,117 @@
+// Copyright 2012 Gary Burd
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package redis
+
+import (
+	"errors"
+	"time"
+)
+
+// Error represents an error returned in a command reply.
+type Error string
+
+func (err Error) Error() string { return string(err) }
+
+// Conn represents a connection to a Redis server.
+type Conn interface {
+	// Close closes the connection.
+	Close() error
+
+	// Err returns a non-nil value when the connection is not usable.
+	Err() error
+
+	// Do sends a command to the server and returns the received reply.
+	Do(commandName string, args ...interface{}) (reply interface{}, err error)
+
+	// Send writes the command to the client's output buffer.
+	Send(commandName string, args ...interface{}) error
+
+	// Flush flushes the output buffer to the Redis server.
+	Flush() error
+
+	// Receive receives a single reply from the Redis server
+	Receive() (reply interface{}, err error)
+}
+
+// Argument is the interface implemented by an object which wants to control how
+// the object is converted to Redis bulk strings.
+type Argument interface {
+	// RedisArg returns a value to be encoded as a bulk string per the
+	// conversions listed in the section 'Executing Commands'.
+	// Implementations should typically return a []byte or string.
+	RedisArg() interface{}
+}
+
+// Scanner is implemented by an object which wants to control its value is
+// interpreted when read from Redis.
+type Scanner interface {
+	// RedisScan assigns a value from a Redis value. The argument src is one of
+	// the reply types listed in the section `Executing Commands`.
+	//
+	// An error should be returned if the value cannot be stored without
+	// loss of information.
+	RedisScan(src interface{}) error
+}
+
+// ConnWithTimeout is an optional interface that allows the caller to override
+// a connection's default read timeout. This interface is useful for executing
+// the BLPOP, BRPOP, BRPOPLPUSH, XREAD and other commands that block at the
+// server.
+//
+// A connection's default read timeout is set with the DialReadTimeout dial
+// option. Applications should rely on the default timeout for commands that do
+// not block at the server.
+//
+// All of the Conn implementations in this package satisfy the ConnWithTimeout
+// interface.
+//
+// Use the DoWithTimeout and ReceiveWithTimeout helper functions to simplify
+// use of this interface.
+type ConnWithTimeout interface {
+	Conn
+
+	// Do sends a command to the server and returns the received reply.
+	// The timeout overrides the read timeout set when dialing the
+	// connection.
+	DoWithTimeout(timeout time.Duration, commandName string, args ...interface{}) (reply interface{}, err error)
+
+	// Receive receives a single reply from the Redis server. The timeout
+	// overrides the read timeout set when dialing the connection.
+	ReceiveWithTimeout(timeout time.Duration) (reply interface{}, err error)
+}
+
+var errTimeoutNotSupported = errors.New("redis: connection does not support ConnWithTimeout")
+
+// DoWithTimeout executes a Redis command with the specified read timeout. If
+// the connection does not satisfy the ConnWithTimeout interface, then an error
+// is returned.
+func DoWithTimeout(c Conn, timeout time.Duration, cmd string, args ...interface{}) (interface{}, error) {
+	cwt, ok := c.(ConnWithTimeout)
+	if !ok {
+		return nil, errTimeoutNotSupported
+	}
+	return cwt.DoWithTimeout(timeout, cmd, args...)
+}
+
+// ReceiveWithTimeout receives a reply with the specified read timeout. If the
+// connection does not satisfy the ConnWithTimeout interface, then an error is
+// returned.
+func ReceiveWithTimeout(c Conn, timeout time.Duration) (interface{}, error) {
+	cwt, ok := c.(ConnWithTimeout)
+	if !ok {
+		return nil, errTimeoutNotSupported
+	}
+	return cwt.ReceiveWithTimeout(timeout)
+}

+ 479 - 0
vendor/github.com/gomodule/redigo/redis/reply.go

@@ -0,0 +1,479 @@
+// Copyright 2012 Gary Burd
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package redis
+
+import (
+	"errors"
+	"fmt"
+	"strconv"
+)
+
+// ErrNil indicates that a reply value is nil.
+var ErrNil = errors.New("redigo: nil returned")
+
+// Int is a helper that converts a command reply to an integer. If err is not
+// equal to nil, then Int returns 0, err. Otherwise, Int converts the
+// reply to an int as follows:
+//
+//  Reply type    Result
+//  integer       int(reply), nil
+//  bulk string   parsed reply, nil
+//  nil           0, ErrNil
+//  other         0, error
+func Int(reply interface{}, err error) (int, error) {
+	if err != nil {
+		return 0, err
+	}
+	switch reply := reply.(type) {
+	case int64:
+		x := int(reply)
+		if int64(x) != reply {
+			return 0, strconv.ErrRange
+		}
+		return x, nil
+	case []byte:
+		n, err := strconv.ParseInt(string(reply), 10, 0)
+		return int(n), err
+	case nil:
+		return 0, ErrNil
+	case Error:
+		return 0, reply
+	}
+	return 0, fmt.Errorf("redigo: unexpected type for Int, got type %T", reply)
+}
+
+// Int64 is a helper that converts a command reply to 64 bit integer. If err is
+// not equal to nil, then Int returns 0, err. Otherwise, Int64 converts the
+// reply to an int64 as follows:
+//
+//  Reply type    Result
+//  integer       reply, nil
+//  bulk string   parsed reply, nil
+//  nil           0, ErrNil
+//  other         0, error
+func Int64(reply interface{}, err error) (int64, error) {
+	if err != nil {
+		return 0, err
+	}
+	switch reply := reply.(type) {
+	case int64:
+		return reply, nil
+	case []byte:
+		n, err := strconv.ParseInt(string(reply), 10, 64)
+		return n, err
+	case nil:
+		return 0, ErrNil
+	case Error:
+		return 0, reply
+	}
+	return 0, fmt.Errorf("redigo: unexpected type for Int64, got type %T", reply)
+}
+
+var errNegativeInt = errors.New("redigo: unexpected value for Uint64")
+
+// Uint64 is a helper that converts a command reply to 64 bit integer. If err is
+// not equal to nil, then Int returns 0, err. Otherwise, Int64 converts the
+// reply to an int64 as follows:
+//
+//  Reply type    Result
+//  integer       reply, nil
+//  bulk string   parsed reply, nil
+//  nil           0, ErrNil
+//  other         0, error
+func Uint64(reply interface{}, err error) (uint64, error) {
+	if err != nil {
+		return 0, err
+	}
+	switch reply := reply.(type) {
+	case int64:
+		if reply < 0 {
+			return 0, errNegativeInt
+		}
+		return uint64(reply), nil
+	case []byte:
+		n, err := strconv.ParseUint(string(reply), 10, 64)
+		return n, err
+	case nil:
+		return 0, ErrNil
+	case Error:
+		return 0, reply
+	}
+	return 0, fmt.Errorf("redigo: unexpected type for Uint64, got type %T", reply)
+}
+
+// Float64 is a helper that converts a command reply to 64 bit float. If err is
+// not equal to nil, then Float64 returns 0, err. Otherwise, Float64 converts
+// the reply to an int as follows:
+//
+//  Reply type    Result
+//  bulk string   parsed reply, nil
+//  nil           0, ErrNil
+//  other         0, error
+func Float64(reply interface{}, err error) (float64, error) {
+	if err != nil {
+		return 0, err
+	}
+	switch reply := reply.(type) {
+	case []byte:
+		n, err := strconv.ParseFloat(string(reply), 64)
+		return n, err
+	case nil:
+		return 0, ErrNil
+	case Error:
+		return 0, reply
+	}
+	return 0, fmt.Errorf("redigo: unexpected type for Float64, got type %T", reply)
+}
+
+// String is a helper that converts a command reply to a string. If err is not
+// equal to nil, then String returns "", err. Otherwise String converts the
+// reply to a string as follows:
+//
+//  Reply type      Result
+//  bulk string     string(reply), nil
+//  simple string   reply, nil
+//  nil             "",  ErrNil
+//  other           "",  error
+func String(reply interface{}, err error) (string, error) {
+	if err != nil {
+		return "", err
+	}
+	switch reply := reply.(type) {
+	case []byte:
+		return string(reply), nil
+	case string:
+		return reply, nil
+	case nil:
+		return "", ErrNil
+	case Error:
+		return "", reply
+	}
+	return "", fmt.Errorf("redigo: unexpected type for String, got type %T", reply)
+}
+
+// Bytes is a helper that converts a command reply to a slice of bytes. If err
+// is not equal to nil, then Bytes returns nil, err. Otherwise Bytes converts
+// the reply to a slice of bytes as follows:
+//
+//  Reply type      Result
+//  bulk string     reply, nil
+//  simple string   []byte(reply), nil
+//  nil             nil, ErrNil
+//  other           nil, error
+func Bytes(reply interface{}, err error) ([]byte, error) {
+	if err != nil {
+		return nil, err
+	}
+	switch reply := reply.(type) {
+	case []byte:
+		return reply, nil
+	case string:
+		return []byte(reply), nil
+	case nil:
+		return nil, ErrNil
+	case Error:
+		return nil, reply
+	}
+	return nil, fmt.Errorf("redigo: unexpected type for Bytes, got type %T", reply)
+}
+
+// Bool is a helper that converts a command reply to a boolean. If err is not
+// equal to nil, then Bool returns false, err. Otherwise Bool converts the
+// reply to boolean as follows:
+//
+//  Reply type      Result
+//  integer         value != 0, nil
+//  bulk string     strconv.ParseBool(reply)
+//  nil             false, ErrNil
+//  other           false, error
+func Bool(reply interface{}, err error) (bool, error) {
+	if err != nil {
+		return false, err
+	}
+	switch reply := reply.(type) {
+	case int64:
+		return reply != 0, nil
+	case []byte:
+		return strconv.ParseBool(string(reply))
+	case nil:
+		return false, ErrNil
+	case Error:
+		return false, reply
+	}
+	return false, fmt.Errorf("redigo: unexpected type for Bool, got type %T", reply)
+}
+
+// MultiBulk is a helper that converts an array command reply to a []interface{}.
+//
+// Deprecated: Use Values instead.
+func MultiBulk(reply interface{}, err error) ([]interface{}, error) { return Values(reply, err) }
+
+// Values is a helper that converts an array command reply to a []interface{}.
+// If err is not equal to nil, then Values returns nil, err. Otherwise, Values
+// converts the reply as follows:
+//
+//  Reply type      Result
+//  array           reply, nil
+//  nil             nil, ErrNil
+//  other           nil, error
+func Values(reply interface{}, err error) ([]interface{}, error) {
+	if err != nil {
+		return nil, err
+	}
+	switch reply := reply.(type) {
+	case []interface{}:
+		return reply, nil
+	case nil:
+		return nil, ErrNil
+	case Error:
+		return nil, reply
+	}
+	return nil, fmt.Errorf("redigo: unexpected type for Values, got type %T", reply)
+}
+
+func sliceHelper(reply interface{}, err error, name string, makeSlice func(int), assign func(int, interface{}) error) error {
+	if err != nil {
+		return err
+	}
+	switch reply := reply.(type) {
+	case []interface{}:
+		makeSlice(len(reply))
+		for i := range reply {
+			if reply[i] == nil {
+				continue
+			}
+			if err := assign(i, reply[i]); err != nil {
+				return err
+			}
+		}
+		return nil
+	case nil:
+		return ErrNil
+	case Error:
+		return reply
+	}
+	return fmt.Errorf("redigo: unexpected type for %s, got type %T", name, reply)
+}
+
+// Float64s is a helper that converts an array command reply to a []float64. If
+// err is not equal to nil, then Float64s returns nil, err. Nil array items are
+// converted to 0 in the output slice. Floats64 returns an error if an array
+// item is not a bulk string or nil.
+func Float64s(reply interface{}, err error) ([]float64, error) {
+	var result []float64
+	err = sliceHelper(reply, err, "Float64s", func(n int) { result = make([]float64, n) }, func(i int, v interface{}) error {
+		p, ok := v.([]byte)
+		if !ok {
+			return fmt.Errorf("redigo: unexpected element type for Floats64, got type %T", v)
+		}
+		f, err := strconv.ParseFloat(string(p), 64)
+		result[i] = f
+		return err
+	})
+	return result, err
+}
+
+// Strings is a helper that converts an array command reply to a []string. If
+// err is not equal to nil, then Strings returns nil, err. Nil array items are
+// converted to "" in the output slice. Strings returns an error if an array
+// item is not a bulk string or nil.
+func Strings(reply interface{}, err error) ([]string, error) {
+	var result []string
+	err = sliceHelper(reply, err, "Strings", func(n int) { result = make([]string, n) }, func(i int, v interface{}) error {
+		switch v := v.(type) {
+		case string:
+			result[i] = v
+			return nil
+		case []byte:
+			result[i] = string(v)
+			return nil
+		default:
+			return fmt.Errorf("redigo: unexpected element type for Strings, got type %T", v)
+		}
+	})
+	return result, err
+}
+
+// ByteSlices is a helper that converts an array command reply to a [][]byte.
+// If err is not equal to nil, then ByteSlices returns nil, err. Nil array
+// items are stay nil. ByteSlices returns an error if an array item is not a
+// bulk string or nil.
+func ByteSlices(reply interface{}, err error) ([][]byte, error) {
+	var result [][]byte
+	err = sliceHelper(reply, err, "ByteSlices", func(n int) { result = make([][]byte, n) }, func(i int, v interface{}) error {
+		p, ok := v.([]byte)
+		if !ok {
+			return fmt.Errorf("redigo: unexpected element type for ByteSlices, got type %T", v)
+		}
+		result[i] = p
+		return nil
+	})
+	return result, err
+}
+
+// Int64s is a helper that converts an array command reply to a []int64.
+// If err is not equal to nil, then Int64s returns nil, err. Nil array
+// items are stay nil. Int64s returns an error if an array item is not a
+// bulk string or nil.
+func Int64s(reply interface{}, err error) ([]int64, error) {
+	var result []int64
+	err = sliceHelper(reply, err, "Int64s", func(n int) { result = make([]int64, n) }, func(i int, v interface{}) error {
+		switch v := v.(type) {
+		case int64:
+			result[i] = v
+			return nil
+		case []byte:
+			n, err := strconv.ParseInt(string(v), 10, 64)
+			result[i] = n
+			return err
+		default:
+			return fmt.Errorf("redigo: unexpected element type for Int64s, got type %T", v)
+		}
+	})
+	return result, err
+}
+
+// Ints is a helper that converts an array command reply to a []in.
+// If err is not equal to nil, then Ints returns nil, err. Nil array
+// items are stay nil. Ints returns an error if an array item is not a
+// bulk string or nil.
+func Ints(reply interface{}, err error) ([]int, error) {
+	var result []int
+	err = sliceHelper(reply, err, "Ints", func(n int) { result = make([]int, n) }, func(i int, v interface{}) error {
+		switch v := v.(type) {
+		case int64:
+			n := int(v)
+			if int64(n) != v {
+				return strconv.ErrRange
+			}
+			result[i] = n
+			return nil
+		case []byte:
+			n, err := strconv.Atoi(string(v))
+			result[i] = n
+			return err
+		default:
+			return fmt.Errorf("redigo: unexpected element type for Ints, got type %T", v)
+		}
+	})
+	return result, err
+}
+
+// StringMap is a helper that converts an array of strings (alternating key, value)
+// into a map[string]string. The HGETALL and CONFIG GET commands return replies in this format.
+// Requires an even number of values in result.
+func StringMap(result interface{}, err error) (map[string]string, error) {
+	values, err := Values(result, err)
+	if err != nil {
+		return nil, err
+	}
+	if len(values)%2 != 0 {
+		return nil, errors.New("redigo: StringMap expects even number of values result")
+	}
+	m := make(map[string]string, len(values)/2)
+	for i := 0; i < len(values); i += 2 {
+		key, okKey := values[i].([]byte)
+		value, okValue := values[i+1].([]byte)
+		if !okKey || !okValue {
+			return nil, errors.New("redigo: StringMap key not a bulk string value")
+		}
+		m[string(key)] = string(value)
+	}
+	return m, nil
+}
+
+// IntMap is a helper that converts an array of strings (alternating key, value)
+// into a map[string]int. The HGETALL commands return replies in this format.
+// Requires an even number of values in result.
+func IntMap(result interface{}, err error) (map[string]int, error) {
+	values, err := Values(result, err)
+	if err != nil {
+		return nil, err
+	}
+	if len(values)%2 != 0 {
+		return nil, errors.New("redigo: IntMap expects even number of values result")
+	}
+	m := make(map[string]int, len(values)/2)
+	for i := 0; i < len(values); i += 2 {
+		key, ok := values[i].([]byte)
+		if !ok {
+			return nil, errors.New("redigo: IntMap key not a bulk string value")
+		}
+		value, err := Int(values[i+1], nil)
+		if err != nil {
+			return nil, err
+		}
+		m[string(key)] = value
+	}
+	return m, nil
+}
+
+// Int64Map is a helper that converts an array of strings (alternating key, value)
+// into a map[string]int64. The HGETALL commands return replies in this format.
+// Requires an even number of values in result.
+func Int64Map(result interface{}, err error) (map[string]int64, error) {
+	values, err := Values(result, err)
+	if err != nil {
+		return nil, err
+	}
+	if len(values)%2 != 0 {
+		return nil, errors.New("redigo: Int64Map expects even number of values result")
+	}
+	m := make(map[string]int64, len(values)/2)
+	for i := 0; i < len(values); i += 2 {
+		key, ok := values[i].([]byte)
+		if !ok {
+			return nil, errors.New("redigo: Int64Map key not a bulk string value")
+		}
+		value, err := Int64(values[i+1], nil)
+		if err != nil {
+			return nil, err
+		}
+		m[string(key)] = value
+	}
+	return m, nil
+}
+
+// Positions is a helper that converts an array of positions (lat, long)
+// into a [][2]float64. The GEOPOS command returns replies in this format.
+func Positions(result interface{}, err error) ([]*[2]float64, error) {
+	values, err := Values(result, err)
+	if err != nil {
+		return nil, err
+	}
+	positions := make([]*[2]float64, len(values))
+	for i := range values {
+		if values[i] == nil {
+			continue
+		}
+		p, ok := values[i].([]interface{})
+		if !ok {
+			return nil, fmt.Errorf("redigo: unexpected element type for interface slice, got type %T", values[i])
+		}
+		if len(p) != 2 {
+			return nil, fmt.Errorf("redigo: unexpected number of values for a member position, got %d", len(p))
+		}
+		lat, err := Float64(p[0], nil)
+		if err != nil {
+			return nil, err
+		}
+		long, err := Float64(p[1], nil)
+		if err != nil {
+			return nil, err
+		}
+		positions[i] = &[2]float64{lat, long}
+	}
+	return positions, nil
+}

+ 585 - 0
vendor/github.com/gomodule/redigo/redis/scan.go

@@ -0,0 +1,585 @@
+// Copyright 2012 Gary Burd
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package redis
+
+import (
+	"errors"
+	"fmt"
+	"reflect"
+	"strconv"
+	"strings"
+	"sync"
+)
+
+func ensureLen(d reflect.Value, n int) {
+	if n > d.Cap() {
+		d.Set(reflect.MakeSlice(d.Type(), n, n))
+	} else {
+		d.SetLen(n)
+	}
+}
+
+func cannotConvert(d reflect.Value, s interface{}) error {
+	var sname string
+	switch s.(type) {
+	case string:
+		sname = "Redis simple string"
+	case Error:
+		sname = "Redis error"
+	case int64:
+		sname = "Redis integer"
+	case []byte:
+		sname = "Redis bulk string"
+	case []interface{}:
+		sname = "Redis array"
+	default:
+		sname = reflect.TypeOf(s).String()
+	}
+	return fmt.Errorf("cannot convert from %s to %s", sname, d.Type())
+}
+
+func convertAssignBulkString(d reflect.Value, s []byte) (err error) {
+	switch d.Type().Kind() {
+	case reflect.Float32, reflect.Float64:
+		var x float64
+		x, err = strconv.ParseFloat(string(s), d.Type().Bits())
+		d.SetFloat(x)
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		var x int64
+		x, err = strconv.ParseInt(string(s), 10, d.Type().Bits())
+		d.SetInt(x)
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+		var x uint64
+		x, err = strconv.ParseUint(string(s), 10, d.Type().Bits())
+		d.SetUint(x)
+	case reflect.Bool:
+		var x bool
+		x, err = strconv.ParseBool(string(s))
+		d.SetBool(x)
+	case reflect.String:
+		d.SetString(string(s))
+	case reflect.Slice:
+		if d.Type().Elem().Kind() != reflect.Uint8 {
+			err = cannotConvert(d, s)
+		} else {
+			d.SetBytes(s)
+		}
+	default:
+		err = cannotConvert(d, s)
+	}
+	return
+}
+
+func convertAssignInt(d reflect.Value, s int64) (err error) {
+	switch d.Type().Kind() {
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		d.SetInt(s)
+		if d.Int() != s {
+			err = strconv.ErrRange
+			d.SetInt(0)
+		}
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+		if s < 0 {
+			err = strconv.ErrRange
+		} else {
+			x := uint64(s)
+			d.SetUint(x)
+			if d.Uint() != x {
+				err = strconv.ErrRange
+				d.SetUint(0)
+			}
+		}
+	case reflect.Bool:
+		d.SetBool(s != 0)
+	default:
+		err = cannotConvert(d, s)
+	}
+	return
+}
+
+func convertAssignValue(d reflect.Value, s interface{}) (err error) {
+	if d.Kind() != reflect.Ptr {
+		if d.CanAddr() {
+			d2 := d.Addr()
+			if d2.CanInterface() {
+				if scanner, ok := d2.Interface().(Scanner); ok {
+					return scanner.RedisScan(s)
+				}
+			}
+		}
+	} else if d.CanInterface() {
+		// Already a reflect.Ptr
+		if d.IsNil() {
+			d.Set(reflect.New(d.Type().Elem()))
+		}
+		if scanner, ok := d.Interface().(Scanner); ok {
+			return scanner.RedisScan(s)
+		}
+	}
+
+	switch s := s.(type) {
+	case []byte:
+		err = convertAssignBulkString(d, s)
+	case int64:
+		err = convertAssignInt(d, s)
+	default:
+		err = cannotConvert(d, s)
+	}
+	return err
+}
+
+func convertAssignArray(d reflect.Value, s []interface{}) error {
+	if d.Type().Kind() != reflect.Slice {
+		return cannotConvert(d, s)
+	}
+	ensureLen(d, len(s))
+	for i := 0; i < len(s); i++ {
+		if err := convertAssignValue(d.Index(i), s[i]); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func convertAssign(d interface{}, s interface{}) (err error) {
+	if scanner, ok := d.(Scanner); ok {
+		return scanner.RedisScan(s)
+	}
+
+	// Handle the most common destination types using type switches and
+	// fall back to reflection for all other types.
+	switch s := s.(type) {
+	case nil:
+		// ignore
+	case []byte:
+		switch d := d.(type) {
+		case *string:
+			*d = string(s)
+		case *int:
+			*d, err = strconv.Atoi(string(s))
+		case *bool:
+			*d, err = strconv.ParseBool(string(s))
+		case *[]byte:
+			*d = s
+		case *interface{}:
+			*d = s
+		case nil:
+			// skip value
+		default:
+			if d := reflect.ValueOf(d); d.Type().Kind() != reflect.Ptr {
+				err = cannotConvert(d, s)
+			} else {
+				err = convertAssignBulkString(d.Elem(), s)
+			}
+		}
+	case int64:
+		switch d := d.(type) {
+		case *int:
+			x := int(s)
+			if int64(x) != s {
+				err = strconv.ErrRange
+				x = 0
+			}
+			*d = x
+		case *bool:
+			*d = s != 0
+		case *interface{}:
+			*d = s
+		case nil:
+			// skip value
+		default:
+			if d := reflect.ValueOf(d); d.Type().Kind() != reflect.Ptr {
+				err = cannotConvert(d, s)
+			} else {
+				err = convertAssignInt(d.Elem(), s)
+			}
+		}
+	case string:
+		switch d := d.(type) {
+		case *string:
+			*d = s
+		case *interface{}:
+			*d = s
+		case nil:
+			// skip value
+		default:
+			err = cannotConvert(reflect.ValueOf(d), s)
+		}
+	case []interface{}:
+		switch d := d.(type) {
+		case *[]interface{}:
+			*d = s
+		case *interface{}:
+			*d = s
+		case nil:
+			// skip value
+		default:
+			if d := reflect.ValueOf(d); d.Type().Kind() != reflect.Ptr {
+				err = cannotConvert(d, s)
+			} else {
+				err = convertAssignArray(d.Elem(), s)
+			}
+		}
+	case Error:
+		err = s
+	default:
+		err = cannotConvert(reflect.ValueOf(d), s)
+	}
+	return
+}
+
+// Scan copies from src to the values pointed at by dest.
+//
+// Scan uses RedisScan if available otherwise:
+//
+// The values pointed at by dest must be an integer, float, boolean, string,
+// []byte, interface{} or slices of these types. Scan uses the standard strconv
+// package to convert bulk strings to numeric and boolean types.
+//
+// If a dest value is nil, then the corresponding src value is skipped.
+//
+// If a src element is nil, then the corresponding dest value is not modified.
+//
+// To enable easy use of Scan in a loop, Scan returns the slice of src
+// following the copied values.
+func Scan(src []interface{}, dest ...interface{}) ([]interface{}, error) {
+	if len(src) < len(dest) {
+		return nil, errors.New("redigo.Scan: array short")
+	}
+	var err error
+	for i, d := range dest {
+		err = convertAssign(d, src[i])
+		if err != nil {
+			err = fmt.Errorf("redigo.Scan: cannot assign to dest %d: %v", i, err)
+			break
+		}
+	}
+	return src[len(dest):], err
+}
+
+type fieldSpec struct {
+	name      string
+	index     []int
+	omitEmpty bool
+}
+
+type structSpec struct {
+	m map[string]*fieldSpec
+	l []*fieldSpec
+}
+
+func (ss *structSpec) fieldSpec(name []byte) *fieldSpec {
+	return ss.m[string(name)]
+}
+
+func compileStructSpec(t reflect.Type, depth map[string]int, index []int, ss *structSpec) {
+	for i := 0; i < t.NumField(); i++ {
+		f := t.Field(i)
+		switch {
+		case f.PkgPath != "" && !f.Anonymous:
+			// Ignore unexported fields.
+		case f.Anonymous:
+			// TODO: Handle pointers. Requires change to decoder and
+			// protection against infinite recursion.
+			if f.Type.Kind() == reflect.Struct {
+				compileStructSpec(f.Type, depth, append(index, i), ss)
+			}
+		default:
+			fs := &fieldSpec{name: f.Name}
+			tag := f.Tag.Get("redis")
+			p := strings.Split(tag, ",")
+			if len(p) > 0 {
+				if p[0] == "-" {
+					continue
+				}
+				if len(p[0]) > 0 {
+					fs.name = p[0]
+				}
+				for _, s := range p[1:] {
+					switch s {
+					case "omitempty":
+						fs.omitEmpty = true
+					default:
+						panic(fmt.Errorf("redigo: unknown field tag %s for type %s", s, t.Name()))
+					}
+				}
+			}
+			d, found := depth[fs.name]
+			if !found {
+				d = 1 << 30
+			}
+			switch {
+			case len(index) == d:
+				// At same depth, remove from result.
+				delete(ss.m, fs.name)
+				j := 0
+				for i := 0; i < len(ss.l); i++ {
+					if fs.name != ss.l[i].name {
+						ss.l[j] = ss.l[i]
+						j += 1
+					}
+				}
+				ss.l = ss.l[:j]
+			case len(index) < d:
+				fs.index = make([]int, len(index)+1)
+				copy(fs.index, index)
+				fs.index[len(index)] = i
+				depth[fs.name] = len(index)
+				ss.m[fs.name] = fs
+				ss.l = append(ss.l, fs)
+			}
+		}
+	}
+}
+
+var (
+	structSpecMutex  sync.RWMutex
+	structSpecCache  = make(map[reflect.Type]*structSpec)
+	defaultFieldSpec = &fieldSpec{}
+)
+
+func structSpecForType(t reflect.Type) *structSpec {
+
+	structSpecMutex.RLock()
+	ss, found := structSpecCache[t]
+	structSpecMutex.RUnlock()
+	if found {
+		return ss
+	}
+
+	structSpecMutex.Lock()
+	defer structSpecMutex.Unlock()
+	ss, found = structSpecCache[t]
+	if found {
+		return ss
+	}
+
+	ss = &structSpec{m: make(map[string]*fieldSpec)}
+	compileStructSpec(t, make(map[string]int), nil, ss)
+	structSpecCache[t] = ss
+	return ss
+}
+
+var errScanStructValue = errors.New("redigo.ScanStruct: value must be non-nil pointer to a struct")
+
+// ScanStruct scans alternating names and values from src to a struct. The
+// HGETALL and CONFIG GET commands return replies in this format.
+//
+// ScanStruct uses exported field names to match values in the response. Use
+// 'redis' field tag to override the name:
+//
+//      Field int `redis:"myName"`
+//
+// Fields with the tag redis:"-" are ignored.
+//
+// Each field uses RedisScan if available otherwise:
+// Integer, float, boolean, string and []byte fields are supported. Scan uses the
+// standard strconv package to convert bulk string values to numeric and
+// boolean types.
+//
+// If a src element is nil, then the corresponding field is not modified.
+func ScanStruct(src []interface{}, dest interface{}) error {
+	d := reflect.ValueOf(dest)
+	if d.Kind() != reflect.Ptr || d.IsNil() {
+		return errScanStructValue
+	}
+	d = d.Elem()
+	if d.Kind() != reflect.Struct {
+		return errScanStructValue
+	}
+	ss := structSpecForType(d.Type())
+
+	if len(src)%2 != 0 {
+		return errors.New("redigo.ScanStruct: number of values not a multiple of 2")
+	}
+
+	for i := 0; i < len(src); i += 2 {
+		s := src[i+1]
+		if s == nil {
+			continue
+		}
+		name, ok := src[i].([]byte)
+		if !ok {
+			return fmt.Errorf("redigo.ScanStruct: key %d not a bulk string value", i)
+		}
+		fs := ss.fieldSpec(name)
+		if fs == nil {
+			continue
+		}
+		if err := convertAssignValue(d.FieldByIndex(fs.index), s); err != nil {
+			return fmt.Errorf("redigo.ScanStruct: cannot assign field %s: %v", fs.name, err)
+		}
+	}
+	return nil
+}
+
+var (
+	errScanSliceValue = errors.New("redigo.ScanSlice: dest must be non-nil pointer to a struct")
+)
+
+// ScanSlice scans src to the slice pointed to by dest. The elements the dest
+// slice must be integer, float, boolean, string, struct or pointer to struct
+// values.
+//
+// Struct fields must be integer, float, boolean or string values. All struct
+// fields are used unless a subset is specified using fieldNames.
+func ScanSlice(src []interface{}, dest interface{}, fieldNames ...string) error {
+	d := reflect.ValueOf(dest)
+	if d.Kind() != reflect.Ptr || d.IsNil() {
+		return errScanSliceValue
+	}
+	d = d.Elem()
+	if d.Kind() != reflect.Slice {
+		return errScanSliceValue
+	}
+
+	isPtr := false
+	t := d.Type().Elem()
+	if t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct {
+		isPtr = true
+		t = t.Elem()
+	}
+
+	if t.Kind() != reflect.Struct {
+		ensureLen(d, len(src))
+		for i, s := range src {
+			if s == nil {
+				continue
+			}
+			if err := convertAssignValue(d.Index(i), s); err != nil {
+				return fmt.Errorf("redigo.ScanSlice: cannot assign element %d: %v", i, err)
+			}
+		}
+		return nil
+	}
+
+	ss := structSpecForType(t)
+	fss := ss.l
+	if len(fieldNames) > 0 {
+		fss = make([]*fieldSpec, len(fieldNames))
+		for i, name := range fieldNames {
+			fss[i] = ss.m[name]
+			if fss[i] == nil {
+				return fmt.Errorf("redigo.ScanSlice: ScanSlice bad field name %s", name)
+			}
+		}
+	}
+
+	if len(fss) == 0 {
+		return errors.New("redigo.ScanSlice: no struct fields")
+	}
+
+	n := len(src) / len(fss)
+	if n*len(fss) != len(src) {
+		return errors.New("redigo.ScanSlice: length not a multiple of struct field count")
+	}
+
+	ensureLen(d, n)
+	for i := 0; i < n; i++ {
+		d := d.Index(i)
+		if isPtr {
+			if d.IsNil() {
+				d.Set(reflect.New(t))
+			}
+			d = d.Elem()
+		}
+		for j, fs := range fss {
+			s := src[i*len(fss)+j]
+			if s == nil {
+				continue
+			}
+			if err := convertAssignValue(d.FieldByIndex(fs.index), s); err != nil {
+				return fmt.Errorf("redigo.ScanSlice: cannot assign element %d to field %s: %v", i*len(fss)+j, fs.name, err)
+			}
+		}
+	}
+	return nil
+}
+
+// Args is a helper for constructing command arguments from structured values.
+type Args []interface{}
+
+// Add returns the result of appending value to args.
+func (args Args) Add(value ...interface{}) Args {
+	return append(args, value...)
+}
+
+// AddFlat returns the result of appending the flattened value of v to args.
+//
+// Maps are flattened by appending the alternating keys and map values to args.
+//
+// Slices are flattened by appending the slice elements to args.
+//
+// Structs are flattened by appending the alternating names and values of
+// exported fields to args. If v is a nil struct pointer, then nothing is
+// appended. The 'redis' field tag overrides struct field names. See ScanStruct
+// for more information on the use of the 'redis' field tag.
+//
+// Other types are appended to args as is.
+func (args Args) AddFlat(v interface{}) Args {
+	rv := reflect.ValueOf(v)
+	switch rv.Kind() {
+	case reflect.Struct:
+		args = flattenStruct(args, rv)
+	case reflect.Slice:
+		for i := 0; i < rv.Len(); i++ {
+			args = append(args, rv.Index(i).Interface())
+		}
+	case reflect.Map:
+		for _, k := range rv.MapKeys() {
+			args = append(args, k.Interface(), rv.MapIndex(k).Interface())
+		}
+	case reflect.Ptr:
+		if rv.Type().Elem().Kind() == reflect.Struct {
+			if !rv.IsNil() {
+				args = flattenStruct(args, rv.Elem())
+			}
+		} else {
+			args = append(args, v)
+		}
+	default:
+		args = append(args, v)
+	}
+	return args
+}
+
+func flattenStruct(args Args, v reflect.Value) Args {
+	ss := structSpecForType(v.Type())
+	for _, fs := range ss.l {
+		fv := v.FieldByIndex(fs.index)
+		if fs.omitEmpty {
+			var empty = false
+			switch fv.Kind() {
+			case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
+				empty = fv.Len() == 0
+			case reflect.Bool:
+				empty = !fv.Bool()
+			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+				empty = fv.Int() == 0
+			case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+				empty = fv.Uint() == 0
+			case reflect.Float32, reflect.Float64:
+				empty = fv.Float() == 0
+			case reflect.Interface, reflect.Ptr:
+				empty = fv.IsNil()
+			}
+			if empty {
+				continue
+			}
+		}
+		args = append(args, fs.name, fv.Interface())
+	}
+	return args
+}

+ 91 - 0
vendor/github.com/gomodule/redigo/redis/script.go

@@ -0,0 +1,91 @@
+// Copyright 2012 Gary Burd
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package redis
+
+import (
+	"crypto/sha1"
+	"encoding/hex"
+	"io"
+	"strings"
+)
+
+// Script encapsulates the source, hash and key count for a Lua script. See
+// http://redis.io/commands/eval for information on scripts in Redis.
+type Script struct {
+	keyCount int
+	src      string
+	hash     string
+}
+
+// NewScript returns a new script object. If keyCount is greater than or equal
+// to zero, then the count is automatically inserted in the EVAL command
+// argument list. If keyCount is less than zero, then the application supplies
+// the count as the first value in the keysAndArgs argument to the Do, Send and
+// SendHash methods.
+func NewScript(keyCount int, src string) *Script {
+	h := sha1.New()
+	io.WriteString(h, src)
+	return &Script{keyCount, src, hex.EncodeToString(h.Sum(nil))}
+}
+
+func (s *Script) args(spec string, keysAndArgs []interface{}) []interface{} {
+	var args []interface{}
+	if s.keyCount < 0 {
+		args = make([]interface{}, 1+len(keysAndArgs))
+		args[0] = spec
+		copy(args[1:], keysAndArgs)
+	} else {
+		args = make([]interface{}, 2+len(keysAndArgs))
+		args[0] = spec
+		args[1] = s.keyCount
+		copy(args[2:], keysAndArgs)
+	}
+	return args
+}
+
+// Hash returns the script hash.
+func (s *Script) Hash() string {
+	return s.hash
+}
+
+// Do evaluates the script. Under the covers, Do optimistically evaluates the
+// script using the EVALSHA command. If the command fails because the script is
+// not loaded, then Do evaluates the script using the EVAL command (thus
+// causing the script to load).
+func (s *Script) Do(c Conn, keysAndArgs ...interface{}) (interface{}, error) {
+	v, err := c.Do("EVALSHA", s.args(s.hash, keysAndArgs)...)
+	if e, ok := err.(Error); ok && strings.HasPrefix(string(e), "NOSCRIPT ") {
+		v, err = c.Do("EVAL", s.args(s.src, keysAndArgs)...)
+	}
+	return v, err
+}
+
+// SendHash evaluates the script without waiting for the reply. The script is
+// evaluated with the EVALSHA command. The application must ensure that the
+// script is loaded by a previous call to Send, Do or Load methods.
+func (s *Script) SendHash(c Conn, keysAndArgs ...interface{}) error {
+	return c.Send("EVALSHA", s.args(s.hash, keysAndArgs)...)
+}
+
+// Send evaluates the script without waiting for the reply.
+func (s *Script) Send(c Conn, keysAndArgs ...interface{}) error {
+	return c.Send("EVAL", s.args(s.src, keysAndArgs)...)
+}
+
+// Load loads the script without evaluating it.
+func (s *Script) Load(c Conn) error {
+	_, err := c.Do("SCRIPT", "LOAD", s.src)
+	return err
+}

+ 27 - 0
vendor/github.com/gorilla/context/LICENSE

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

+ 10 - 0
vendor/github.com/gorilla/context/README.md

@@ -0,0 +1,10 @@
+context
+=======
+[![Build Status](https://travis-ci.org/gorilla/context.png?branch=master)](https://travis-ci.org/gorilla/context)
+
+gorilla/context is a general purpose registry for global request variables.
+
+> Note: gorilla/context, having been born well before `context.Context` existed, does not play well
+> with the shallow copying of the request that [`http.Request.WithContext`](https://golang.org/pkg/net/http/#Request.WithContext) (added to net/http Go 1.7 onwards) performs. You should either use *just* gorilla/context, or moving forward, the new `http.Request.Context()`.
+
+Read the full documentation here: http://www.gorillatoolkit.org/pkg/context

+ 143 - 0
vendor/github.com/gorilla/context/context.go

@@ -0,0 +1,143 @@
+// Copyright 2012 The Gorilla Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package context
+
+import (
+	"net/http"
+	"sync"
+	"time"
+)
+
+var (
+	mutex sync.RWMutex
+	data  = make(map[*http.Request]map[interface{}]interface{})
+	datat = make(map[*http.Request]int64)
+)
+
+// Set stores a value for a given key in a given request.
+func Set(r *http.Request, key, val interface{}) {
+	mutex.Lock()
+	if data[r] == nil {
+		data[r] = make(map[interface{}]interface{})
+		datat[r] = time.Now().Unix()
+	}
+	data[r][key] = val
+	mutex.Unlock()
+}
+
+// Get returns a value stored for a given key in a given request.
+func Get(r *http.Request, key interface{}) interface{} {
+	mutex.RLock()
+	if ctx := data[r]; ctx != nil {
+		value := ctx[key]
+		mutex.RUnlock()
+		return value
+	}
+	mutex.RUnlock()
+	return nil
+}
+
+// GetOk returns stored value and presence state like multi-value return of map access.
+func GetOk(r *http.Request, key interface{}) (interface{}, bool) {
+	mutex.RLock()
+	if _, ok := data[r]; ok {
+		value, ok := data[r][key]
+		mutex.RUnlock()
+		return value, ok
+	}
+	mutex.RUnlock()
+	return nil, false
+}
+
+// GetAll returns all stored values for the request as a map. Nil is returned for invalid requests.
+func GetAll(r *http.Request) map[interface{}]interface{} {
+	mutex.RLock()
+	if context, ok := data[r]; ok {
+		result := make(map[interface{}]interface{}, len(context))
+		for k, v := range context {
+			result[k] = v
+		}
+		mutex.RUnlock()
+		return result
+	}
+	mutex.RUnlock()
+	return nil
+}
+
+// GetAllOk returns all stored values for the request as a map and a boolean value that indicates if
+// the request was registered.
+func GetAllOk(r *http.Request) (map[interface{}]interface{}, bool) {
+	mutex.RLock()
+	context, ok := data[r]
+	result := make(map[interface{}]interface{}, len(context))
+	for k, v := range context {
+		result[k] = v
+	}
+	mutex.RUnlock()
+	return result, ok
+}
+
+// Delete removes a value stored for a given key in a given request.
+func Delete(r *http.Request, key interface{}) {
+	mutex.Lock()
+	if data[r] != nil {
+		delete(data[r], key)
+	}
+	mutex.Unlock()
+}
+
+// Clear removes all values stored for a given request.
+//
+// This is usually called by a handler wrapper to clean up request
+// variables at the end of a request lifetime. See ClearHandler().
+func Clear(r *http.Request) {
+	mutex.Lock()
+	clear(r)
+	mutex.Unlock()
+}
+
+// clear is Clear without the lock.
+func clear(r *http.Request) {
+	delete(data, r)
+	delete(datat, r)
+}
+
+// Purge removes request data stored for longer than maxAge, in seconds.
+// It returns the amount of requests removed.
+//
+// If maxAge <= 0, all request data is removed.
+//
+// This is only used for sanity check: in case context cleaning was not
+// properly set some request data can be kept forever, consuming an increasing
+// amount of memory. In case this is detected, Purge() must be called
+// periodically until the problem is fixed.
+func Purge(maxAge int) int {
+	mutex.Lock()
+	count := 0
+	if maxAge <= 0 {
+		count = len(data)
+		data = make(map[*http.Request]map[interface{}]interface{})
+		datat = make(map[*http.Request]int64)
+	} else {
+		min := time.Now().Unix() - int64(maxAge)
+		for r := range data {
+			if datat[r] < min {
+				clear(r)
+				count++
+			}
+		}
+	}
+	mutex.Unlock()
+	return count
+}
+
+// ClearHandler wraps an http.Handler and clears request values at the end
+// of a request lifetime.
+func ClearHandler(h http.Handler) http.Handler {
+	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		defer Clear(r)
+		h.ServeHTTP(w, r)
+	})
+}

+ 88 - 0
vendor/github.com/gorilla/context/doc.go

@@ -0,0 +1,88 @@
+// Copyright 2012 The Gorilla Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Package context stores values shared during a request lifetime.
+
+Note: gorilla/context, having been born well before `context.Context` existed,
+does not play well > with the shallow copying of the request that
+[`http.Request.WithContext`](https://golang.org/pkg/net/http/#Request.WithContext)
+(added to net/http Go 1.7 onwards) performs. You should either use *just*
+gorilla/context, or moving forward, the new `http.Request.Context()`.
+
+For example, a router can set variables extracted from the URL and later
+application handlers can access those values, or it can be used to store
+sessions values to be saved at the end of a request. There are several
+others common uses.
+
+The idea was posted by Brad Fitzpatrick to the go-nuts mailing list:
+
+	http://groups.google.com/group/golang-nuts/msg/e2d679d303aa5d53
+
+Here's the basic usage: first define the keys that you will need. The key
+type is interface{} so a key can be of any type that supports equality.
+Here we define a key using a custom int type to avoid name collisions:
+
+	package foo
+
+	import (
+		"github.com/gorilla/context"
+	)
+
+	type key int
+
+	const MyKey key = 0
+
+Then set a variable. Variables are bound to an http.Request object, so you
+need a request instance to set a value:
+
+	context.Set(r, MyKey, "bar")
+
+The application can later access the variable using the same key you provided:
+
+	func MyHandler(w http.ResponseWriter, r *http.Request) {
+		// val is "bar".
+		val := context.Get(r, foo.MyKey)
+
+		// returns ("bar", true)
+		val, ok := context.GetOk(r, foo.MyKey)
+		// ...
+	}
+
+And that's all about the basic usage. We discuss some other ideas below.
+
+Any type can be stored in the context. To enforce a given type, make the key
+private and wrap Get() and Set() to accept and return values of a specific
+type:
+
+	type key int
+
+	const mykey key = 0
+
+	// GetMyKey returns a value for this package from the request values.
+	func GetMyKey(r *http.Request) SomeType {
+		if rv := context.Get(r, mykey); rv != nil {
+			return rv.(SomeType)
+		}
+		return nil
+	}
+
+	// SetMyKey sets a value for this package in the request values.
+	func SetMyKey(r *http.Request, val SomeType) {
+		context.Set(r, mykey, val)
+	}
+
+Variables must be cleared at the end of a request, to remove all values
+that were stored. This can be done in an http.Handler, after a request was
+served. Just call Clear() passing the request:
+
+	context.Clear(r)
+
+...or use ClearHandler(), which conveniently wraps an http.Handler to clear
+variables at the end of a request lifetime.
+
+The Routers from the packages gorilla/mux and gorilla/pat call Clear()
+so if you are using either of them you don't need to clear the context manually.
+*/
+package context

+ 19 - 0
vendor/github.com/gorilla/securecookie/AUTHORS

@@ -0,0 +1,19 @@
+# This is the official list of gorilla/securecookie authors for copyright purposes.
+# Please keep the list sorted.
+
+0x434D53 <christoph.seufert@gmail.com>
+Abdülhamit Yilmaz <mr.yilmaz@gmx.de>
+Annonomus-Penguin <Annonomus-Penguin@users.noreply.github.com>
+Craig Peterson <cpeterson@stackoverflow.com>
+Cyril David <cyx@cyx.is>
+Dmitry Chestnykh <dmitry@codingrobots.com>
+Dominik Honnef <dominikh@fork-bomb.org>
+Google LLC (https://opensource.google.com/)
+John Downey <john@jtdowney.com>
+Kamil Kisiel <kamil@kamilkisiel.net>
+Keunwoo Lee <keunwoo@flux.io>
+Mahmud Ridwan <m@hjr265.me>
+Matt Silverlock <matt@eatsleeprepeat.net>
+rodrigo moraes <rodrigo.moraes@gmail.com>
+s7v7nislands <s7v7nislands@gmail.com>
+Wesley Bitter <github@wessie.info>

+ 27 - 0
vendor/github.com/gorilla/securecookie/LICENSE

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

+ 82 - 0
vendor/github.com/gorilla/securecookie/README.md

@@ -0,0 +1,82 @@
+# securecookie
+
+[![GoDoc](https://godoc.org/github.com/gorilla/securecookie?status.svg)](https://godoc.org/github.com/gorilla/securecookie) [![Build Status](https://travis-ci.org/gorilla/securecookie.png?branch=master)](https://travis-ci.org/gorilla/securecookie)
+[![Sourcegraph](https://sourcegraph.com/github.com/gorilla/securecookie/-/badge.svg)](https://sourcegraph.com/github.com/gorilla/securecookie?badge)
+
+securecookie encodes and decodes authenticated and optionally encrypted
+cookie values.
+
+Secure cookies can't be forged, because their values are validated using HMAC.
+When encrypted, the content is also inaccessible to malicious eyes. It is still
+recommended that sensitive data not be stored in cookies, and that HTTPS be used
+to prevent cookie [replay attacks](https://en.wikipedia.org/wiki/Replay_attack).
+
+## Examples
+
+To use it, first create a new SecureCookie instance:
+
+```go
+// Hash keys should be at least 32 bytes long
+var hashKey = []byte("very-secret")
+// Block keys should be 16 bytes (AES-128) or 32 bytes (AES-256) long.
+// Shorter keys may weaken the encryption used.
+var blockKey = []byte("a-lot-secret")
+var s = securecookie.New(hashKey, blockKey)
+```
+
+The hashKey is required, used to authenticate the cookie value using HMAC.
+It is recommended to use a key with 32 or 64 bytes.
+
+The blockKey is optional, used to encrypt the cookie value -- set it to nil
+to not use encryption. If set, the length must correspond to the block size
+of the encryption algorithm. For AES, used by default, valid lengths are
+16, 24, or 32 bytes to select AES-128, AES-192, or AES-256.
+
+Strong keys can be created using the convenience function
+`GenerateRandomKey()`. Note that keys created using `GenerateRandomKey()` are not
+automatically persisted. New keys will be created when the application is
+restarted, and previously issued cookies will not be able to be decoded.
+
+Once a SecureCookie instance is set, use it to encode a cookie value:
+
+```go
+func SetCookieHandler(w http.ResponseWriter, r *http.Request) {
+	value := map[string]string{
+		"foo": "bar",
+	}
+	if encoded, err := s.Encode("cookie-name", value); err == nil {
+		cookie := &http.Cookie{
+			Name:  "cookie-name",
+			Value: encoded,
+			Path:  "/",
+			Secure: true,
+			HttpOnly: true,
+		}
+		http.SetCookie(w, cookie)
+	}
+}
+```
+
+Later, use the same SecureCookie instance to decode and validate a cookie
+value:
+
+```go
+func ReadCookieHandler(w http.ResponseWriter, r *http.Request) {
+	if cookie, err := r.Cookie("cookie-name"); err == nil {
+		value := make(map[string]string)
+		if err = s2.Decode("cookie-name", cookie.Value, &value); err == nil {
+			fmt.Fprintf(w, "The value of foo is %q", value["foo"])
+		}
+	}
+}
+```
+
+We stored a map[string]string, but secure cookies can hold any value that
+can be encoded using `encoding/gob`. To store custom types, they must be
+registered first using gob.Register(). For basic types this is not needed;
+it works out of the box. An optional JSON encoder that uses `encoding/json` is
+available for types compatible with JSON.
+
+## License
+
+BSD licensed. See the LICENSE file for details.

+ 61 - 0
vendor/github.com/gorilla/securecookie/doc.go

@@ -0,0 +1,61 @@
+// Copyright 2012 The Gorilla Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Package securecookie encodes and decodes authenticated and optionally
+encrypted cookie values.
+
+Secure cookies can't be forged, because their values are validated using HMAC.
+When encrypted, the content is also inaccessible to malicious eyes.
+
+To use it, first create a new SecureCookie instance:
+
+	var hashKey = []byte("very-secret")
+	var blockKey = []byte("a-lot-secret")
+	var s = securecookie.New(hashKey, blockKey)
+
+The hashKey is required, used to authenticate the cookie value using HMAC.
+It is recommended to use a key with 32 or 64 bytes.
+
+The blockKey is optional, used to encrypt the cookie value -- set it to nil
+to not use encryption. If set, the length must correspond to the block size
+of the encryption algorithm. For AES, used by default, valid lengths are
+16, 24, or 32 bytes to select AES-128, AES-192, or AES-256.
+
+Strong keys can be created using the convenience function GenerateRandomKey().
+
+Once a SecureCookie instance is set, use it to encode a cookie value:
+
+	func SetCookieHandler(w http.ResponseWriter, r *http.Request) {
+		value := map[string]string{
+			"foo": "bar",
+		}
+		if encoded, err := s.Encode("cookie-name", value); err == nil {
+			cookie := &http.Cookie{
+				Name:  "cookie-name",
+				Value: encoded,
+				Path:  "/",
+			}
+			http.SetCookie(w, cookie)
+		}
+	}
+
+Later, use the same SecureCookie instance to decode and validate a cookie
+value:
+
+	func ReadCookieHandler(w http.ResponseWriter, r *http.Request) {
+		if cookie, err := r.Cookie("cookie-name"); err == nil {
+			value := make(map[string]string)
+			if err = s2.Decode("cookie-name", cookie.Value, &value); err == nil {
+				fmt.Fprintf(w, "The value of foo is %q", value["foo"])
+			}
+		}
+	}
+
+We stored a map[string]string, but secure cookies can hold any value that
+can be encoded using encoding/gob. To store custom types, they must be
+registered first using gob.Register(). For basic types this is not needed;
+it works out of the box.
+*/
+package securecookie

+ 25 - 0
vendor/github.com/gorilla/securecookie/fuzz.go

@@ -0,0 +1,25 @@
+// +build gofuzz
+
+package securecookie
+
+var hashKey = []byte("very-secret12345")
+var blockKey = []byte("a-lot-secret1234")
+var s = New(hashKey, blockKey)
+
+type Cookie struct {
+	B bool
+	I int
+	S string
+}
+
+func Fuzz(data []byte) int {
+	datas := string(data)
+	var c Cookie
+	if err := s.Decode("fuzz", datas, &c); err != nil {
+		return 0
+	}
+	if _, err := s.Encode("fuzz", c); err != nil {
+		panic(err)
+	}
+	return 1
+}

+ 1 - 0
vendor/github.com/gorilla/securecookie/go.mod

@@ -0,0 +1 @@
+module github.com/gorilla/securecookie

+ 650 - 0
vendor/github.com/gorilla/securecookie/securecookie.go

@@ -0,0 +1,650 @@
+// Copyright 2012 The Gorilla Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package securecookie
+
+import (
+	"bytes"
+	"crypto/aes"
+	"crypto/cipher"
+	"crypto/hmac"
+	"crypto/rand"
+	"crypto/sha256"
+	"crypto/subtle"
+	"encoding/base64"
+	"encoding/gob"
+	"encoding/json"
+	"fmt"
+	"hash"
+	"io"
+	"strconv"
+	"strings"
+	"time"
+)
+
+// Error is the interface of all errors returned by functions in this library.
+type Error interface {
+	error
+
+	// IsUsage returns true for errors indicating the client code probably
+	// uses this library incorrectly.  For example, the client may have
+	// failed to provide a valid hash key, or may have failed to configure
+	// the Serializer adequately for encoding value.
+	IsUsage() bool
+
+	// IsDecode returns true for errors indicating that a cookie could not
+	// be decoded and validated.  Since cookies are usually untrusted
+	// user-provided input, errors of this type should be expected.
+	// Usually, the proper action is simply to reject the request.
+	IsDecode() bool
+
+	// IsInternal returns true for unexpected errors occurring in the
+	// securecookie implementation.
+	IsInternal() bool
+
+	// Cause, if it returns a non-nil value, indicates that this error was
+	// propagated from some underlying library.  If this method returns nil,
+	// this error was raised directly by this library.
+	//
+	// Cause is provided principally for debugging/logging purposes; it is
+	// rare that application logic should perform meaningfully different
+	// logic based on Cause.  See, for example, the caveats described on
+	// (MultiError).Cause().
+	Cause() error
+}
+
+// errorType is a bitmask giving the error type(s) of an cookieError value.
+type errorType int
+
+const (
+	usageError = errorType(1 << iota)
+	decodeError
+	internalError
+)
+
+type cookieError struct {
+	typ   errorType
+	msg   string
+	cause error
+}
+
+func (e cookieError) IsUsage() bool    { return (e.typ & usageError) != 0 }
+func (e cookieError) IsDecode() bool   { return (e.typ & decodeError) != 0 }
+func (e cookieError) IsInternal() bool { return (e.typ & internalError) != 0 }
+
+func (e cookieError) Cause() error { return e.cause }
+
+func (e cookieError) Error() string {
+	parts := []string{"securecookie: "}
+	if e.msg == "" {
+		parts = append(parts, "error")
+	} else {
+		parts = append(parts, e.msg)
+	}
+	if c := e.Cause(); c != nil {
+		parts = append(parts, " - caused by: ", c.Error())
+	}
+	return strings.Join(parts, "")
+}
+
+var (
+	errGeneratingIV = cookieError{typ: internalError, msg: "failed to generate random iv"}
+
+	errNoCodecs            = cookieError{typ: usageError, msg: "no codecs provided"}
+	errHashKeyNotSet       = cookieError{typ: usageError, msg: "hash key is not set"}
+	errBlockKeyNotSet      = cookieError{typ: usageError, msg: "block key is not set"}
+	errEncodedValueTooLong = cookieError{typ: usageError, msg: "the value is too long"}
+
+	errValueToDecodeTooLong = cookieError{typ: decodeError, msg: "the value is too long"}
+	errTimestampInvalid     = cookieError{typ: decodeError, msg: "invalid timestamp"}
+	errTimestampTooNew      = cookieError{typ: decodeError, msg: "timestamp is too new"}
+	errTimestampExpired     = cookieError{typ: decodeError, msg: "expired timestamp"}
+	errDecryptionFailed     = cookieError{typ: decodeError, msg: "the value could not be decrypted"}
+	errValueNotByte         = cookieError{typ: decodeError, msg: "value not a []byte."}
+	errValueNotBytePtr      = cookieError{typ: decodeError, msg: "value not a pointer to []byte."}
+
+	// ErrMacInvalid indicates that cookie decoding failed because the HMAC
+	// could not be extracted and verified.  Direct use of this error
+	// variable is deprecated; it is public only for legacy compatibility,
+	// and may be privatized in the future, as it is rarely useful to
+	// distinguish between this error and other Error implementations.
+	ErrMacInvalid = cookieError{typ: decodeError, msg: "the value is not valid"}
+)
+
+// Codec defines an interface to encode and decode cookie values.
+type Codec interface {
+	Encode(name string, value interface{}) (string, error)
+	Decode(name, value string, dst interface{}) error
+}
+
+// New returns a new SecureCookie.
+//
+// hashKey is required, used to authenticate values using HMAC. Create it using
+// GenerateRandomKey(). It is recommended to use a key with 32 or 64 bytes.
+//
+// blockKey is optional, used to encrypt values. Create it using
+// GenerateRandomKey(). The key length must correspond to the block size
+// of the encryption algorithm. For AES, used by default, valid lengths are
+// 16, 24, or 32 bytes to select AES-128, AES-192, or AES-256.
+// The default encoder used for cookie serialization is encoding/gob.
+//
+// Note that keys created using GenerateRandomKey() are not automatically
+// persisted. New keys will be created when the application is restarted, and
+// previously issued cookies will not be able to be decoded.
+func New(hashKey, blockKey []byte) *SecureCookie {
+	s := &SecureCookie{
+		hashKey:   hashKey,
+		blockKey:  blockKey,
+		hashFunc:  sha256.New,
+		maxAge:    86400 * 30,
+		maxLength: 4096,
+		sz:        GobEncoder{},
+	}
+	if len(hashKey) == 0 {
+		s.err = errHashKeyNotSet
+	}
+	if blockKey != nil {
+		s.BlockFunc(aes.NewCipher)
+	}
+	return s
+}
+
+// SecureCookie encodes and decodes authenticated and optionally encrypted
+// cookie values.
+type SecureCookie struct {
+	hashKey   []byte
+	hashFunc  func() hash.Hash
+	blockKey  []byte
+	block     cipher.Block
+	maxLength int
+	maxAge    int64
+	minAge    int64
+	err       error
+	sz        Serializer
+	// For testing purposes, the function that returns the current timestamp.
+	// If not set, it will use time.Now().UTC().Unix().
+	timeFunc func() int64
+}
+
+// Serializer provides an interface for providing custom serializers for cookie
+// values.
+type Serializer interface {
+	Serialize(src interface{}) ([]byte, error)
+	Deserialize(src []byte, dst interface{}) error
+}
+
+// GobEncoder encodes cookie values using encoding/gob. This is the simplest
+// encoder and can handle complex types via gob.Register.
+type GobEncoder struct{}
+
+// JSONEncoder encodes cookie values using encoding/json. Users who wish to
+// encode complex types need to satisfy the json.Marshaller and
+// json.Unmarshaller interfaces.
+type JSONEncoder struct{}
+
+// NopEncoder does not encode cookie values, and instead simply accepts a []byte
+// (as an interface{}) and returns a []byte. This is particularly useful when
+// you encoding an object upstream and do not wish to re-encode it.
+type NopEncoder struct{}
+
+// MaxLength restricts the maximum length, in bytes, for the cookie value.
+//
+// Default is 4096, which is the maximum value accepted by Internet Explorer.
+func (s *SecureCookie) MaxLength(value int) *SecureCookie {
+	s.maxLength = value
+	return s
+}
+
+// MaxAge restricts the maximum age, in seconds, for the cookie value.
+//
+// Default is 86400 * 30. Set it to 0 for no restriction.
+func (s *SecureCookie) MaxAge(value int) *SecureCookie {
+	s.maxAge = int64(value)
+	return s
+}
+
+// MinAge restricts the minimum age, in seconds, for the cookie value.
+//
+// Default is 0 (no restriction).
+func (s *SecureCookie) MinAge(value int) *SecureCookie {
+	s.minAge = int64(value)
+	return s
+}
+
+// HashFunc sets the hash function used to create HMAC.
+//
+// Default is crypto/sha256.New.
+func (s *SecureCookie) HashFunc(f func() hash.Hash) *SecureCookie {
+	s.hashFunc = f
+	return s
+}
+
+// BlockFunc sets the encryption function used to create a cipher.Block.
+//
+// Default is crypto/aes.New.
+func (s *SecureCookie) BlockFunc(f func([]byte) (cipher.Block, error)) *SecureCookie {
+	if s.blockKey == nil {
+		s.err = errBlockKeyNotSet
+	} else if block, err := f(s.blockKey); err == nil {
+		s.block = block
+	} else {
+		s.err = cookieError{cause: err, typ: usageError}
+	}
+	return s
+}
+
+// Encoding sets the encoding/serialization method for cookies.
+//
+// Default is encoding/gob.  To encode special structures using encoding/gob,
+// they must be registered first using gob.Register().
+func (s *SecureCookie) SetSerializer(sz Serializer) *SecureCookie {
+	s.sz = sz
+
+	return s
+}
+
+// Encode encodes a cookie value.
+//
+// It serializes, optionally encrypts, signs with a message authentication code,
+// and finally encodes the value.
+//
+// The name argument is the cookie name. It is stored with the encoded value.
+// The value argument is the value to be encoded. It can be any value that can
+// be encoded using the currently selected serializer; see SetSerializer().
+//
+// It is the client's responsibility to ensure that value, when encoded using
+// the current serialization/encryption settings on s and then base64-encoded,
+// is shorter than the maximum permissible length.
+func (s *SecureCookie) Encode(name string, value interface{}) (string, error) {
+	if s.err != nil {
+		return "", s.err
+	}
+	if s.hashKey == nil {
+		s.err = errHashKeyNotSet
+		return "", s.err
+	}
+	var err error
+	var b []byte
+	// 1. Serialize.
+	if b, err = s.sz.Serialize(value); err != nil {
+		return "", cookieError{cause: err, typ: usageError}
+	}
+	// 2. Encrypt (optional).
+	if s.block != nil {
+		if b, err = encrypt(s.block, b); err != nil {
+			return "", cookieError{cause: err, typ: usageError}
+		}
+	}
+	b = encode(b)
+	// 3. Create MAC for "name|date|value". Extra pipe to be used later.
+	b = []byte(fmt.Sprintf("%s|%d|%s|", name, s.timestamp(), b))
+	mac := createMac(hmac.New(s.hashFunc, s.hashKey), b[:len(b)-1])
+	// Append mac, remove name.
+	b = append(b, mac...)[len(name)+1:]
+	// 4. Encode to base64.
+	b = encode(b)
+	// 5. Check length.
+	if s.maxLength != 0 && len(b) > s.maxLength {
+		return "", errEncodedValueTooLong
+	}
+	// Done.
+	return string(b), nil
+}
+
+// Decode decodes a cookie value.
+//
+// It decodes, verifies a message authentication code, optionally decrypts and
+// finally deserializes the value.
+//
+// The name argument is the cookie name. It must be the same name used when
+// it was stored. The value argument is the encoded cookie value. The dst
+// argument is where the cookie will be decoded. It must be a pointer.
+func (s *SecureCookie) Decode(name, value string, dst interface{}) error {
+	if s.err != nil {
+		return s.err
+	}
+	if s.hashKey == nil {
+		s.err = errHashKeyNotSet
+		return s.err
+	}
+	// 1. Check length.
+	if s.maxLength != 0 && len(value) > s.maxLength {
+		return errValueToDecodeTooLong
+	}
+	// 2. Decode from base64.
+	b, err := decode([]byte(value))
+	if err != nil {
+		return err
+	}
+	// 3. Verify MAC. Value is "date|value|mac".
+	parts := bytes.SplitN(b, []byte("|"), 3)
+	if len(parts) != 3 {
+		return ErrMacInvalid
+	}
+	h := hmac.New(s.hashFunc, s.hashKey)
+	b = append([]byte(name+"|"), b[:len(b)-len(parts[2])-1]...)
+	if err = verifyMac(h, b, parts[2]); err != nil {
+		return err
+	}
+	// 4. Verify date ranges.
+	var t1 int64
+	if t1, err = strconv.ParseInt(string(parts[0]), 10, 64); err != nil {
+		return errTimestampInvalid
+	}
+	t2 := s.timestamp()
+	if s.minAge != 0 && t1 > t2-s.minAge {
+		return errTimestampTooNew
+	}
+	if s.maxAge != 0 && t1 < t2-s.maxAge {
+		return errTimestampExpired
+	}
+	// 5. Decrypt (optional).
+	b, err = decode(parts[1])
+	if err != nil {
+		return err
+	}
+	if s.block != nil {
+		if b, err = decrypt(s.block, b); err != nil {
+			return err
+		}
+	}
+	// 6. Deserialize.
+	if err = s.sz.Deserialize(b, dst); err != nil {
+		return cookieError{cause: err, typ: decodeError}
+	}
+	// Done.
+	return nil
+}
+
+// timestamp returns the current timestamp, in seconds.
+//
+// For testing purposes, the function that generates the timestamp can be
+// overridden. If not set, it will return time.Now().UTC().Unix().
+func (s *SecureCookie) timestamp() int64 {
+	if s.timeFunc == nil {
+		return time.Now().UTC().Unix()
+	}
+	return s.timeFunc()
+}
+
+// Authentication -------------------------------------------------------------
+
+// createMac creates a message authentication code (MAC).
+func createMac(h hash.Hash, value []byte) []byte {
+	h.Write(value)
+	return h.Sum(nil)
+}
+
+// verifyMac verifies that a message authentication code (MAC) is valid.
+func verifyMac(h hash.Hash, value []byte, mac []byte) error {
+	mac2 := createMac(h, value)
+	// Check that both MACs are of equal length, as subtle.ConstantTimeCompare
+	// does not do this prior to Go 1.4.
+	if len(mac) == len(mac2) && subtle.ConstantTimeCompare(mac, mac2) == 1 {
+		return nil
+	}
+	return ErrMacInvalid
+}
+
+// Encryption -----------------------------------------------------------------
+
+// encrypt encrypts a value using the given block in counter mode.
+//
+// A random initialization vector (http://goo.gl/zF67k) with the length of the
+// block size is prepended to the resulting ciphertext.
+func encrypt(block cipher.Block, value []byte) ([]byte, error) {
+	iv := GenerateRandomKey(block.BlockSize())
+	if iv == nil {
+		return nil, errGeneratingIV
+	}
+	// Encrypt it.
+	stream := cipher.NewCTR(block, iv)
+	stream.XORKeyStream(value, value)
+	// Return iv + ciphertext.
+	return append(iv, value...), nil
+}
+
+// decrypt decrypts a value using the given block in counter mode.
+//
+// The value to be decrypted must be prepended by a initialization vector
+// (http://goo.gl/zF67k) with the length of the block size.
+func decrypt(block cipher.Block, value []byte) ([]byte, error) {
+	size := block.BlockSize()
+	if len(value) > size {
+		// Extract iv.
+		iv := value[:size]
+		// Extract ciphertext.
+		value = value[size:]
+		// Decrypt it.
+		stream := cipher.NewCTR(block, iv)
+		stream.XORKeyStream(value, value)
+		return value, nil
+	}
+	return nil, errDecryptionFailed
+}
+
+// Serialization --------------------------------------------------------------
+
+// Serialize encodes a value using gob.
+func (e GobEncoder) Serialize(src interface{}) ([]byte, error) {
+	buf := new(bytes.Buffer)
+	enc := gob.NewEncoder(buf)
+	if err := enc.Encode(src); err != nil {
+		return nil, cookieError{cause: err, typ: usageError}
+	}
+	return buf.Bytes(), nil
+}
+
+// Deserialize decodes a value using gob.
+func (e GobEncoder) Deserialize(src []byte, dst interface{}) error {
+	dec := gob.NewDecoder(bytes.NewBuffer(src))
+	if err := dec.Decode(dst); err != nil {
+		return cookieError{cause: err, typ: decodeError}
+	}
+	return nil
+}
+
+// Serialize encodes a value using encoding/json.
+func (e JSONEncoder) Serialize(src interface{}) ([]byte, error) {
+	buf := new(bytes.Buffer)
+	enc := json.NewEncoder(buf)
+	if err := enc.Encode(src); err != nil {
+		return nil, cookieError{cause: err, typ: usageError}
+	}
+	return buf.Bytes(), nil
+}
+
+// Deserialize decodes a value using encoding/json.
+func (e JSONEncoder) Deserialize(src []byte, dst interface{}) error {
+	dec := json.NewDecoder(bytes.NewReader(src))
+	if err := dec.Decode(dst); err != nil {
+		return cookieError{cause: err, typ: decodeError}
+	}
+	return nil
+}
+
+// Serialize passes a []byte through as-is.
+func (e NopEncoder) Serialize(src interface{}) ([]byte, error) {
+	if b, ok := src.([]byte); ok {
+		return b, nil
+	}
+
+	return nil, errValueNotByte
+}
+
+// Deserialize passes a []byte through as-is.
+func (e NopEncoder) Deserialize(src []byte, dst interface{}) error {
+	if dat, ok := dst.(*[]byte); ok {
+		*dat = src
+		return nil
+	}
+	return errValueNotBytePtr
+}
+
+// Encoding -------------------------------------------------------------------
+
+// encode encodes a value using base64.
+func encode(value []byte) []byte {
+	encoded := make([]byte, base64.URLEncoding.EncodedLen(len(value)))
+	base64.URLEncoding.Encode(encoded, value)
+	return encoded
+}
+
+// decode decodes a cookie using base64.
+func decode(value []byte) ([]byte, error) {
+	decoded := make([]byte, base64.URLEncoding.DecodedLen(len(value)))
+	b, err := base64.URLEncoding.Decode(decoded, value)
+	if err != nil {
+		return nil, cookieError{cause: err, typ: decodeError, msg: "base64 decode failed"}
+	}
+	return decoded[:b], nil
+}
+
+// Helpers --------------------------------------------------------------------
+
+// GenerateRandomKey creates a random key with the given length in bytes.
+// On failure, returns nil.
+//
+// Note that keys created using `GenerateRandomKey()` are not automatically
+// persisted. New keys will be created when the application is restarted, and
+// previously issued cookies will not be able to be decoded.
+//
+// Callers should explicitly check for the possibility of a nil return, treat
+// it as a failure of the system random number generator, and not continue.
+func GenerateRandomKey(length int) []byte {
+	k := make([]byte, length)
+	if _, err := io.ReadFull(rand.Reader, k); err != nil {
+		return nil
+	}
+	return k
+}
+
+// CodecsFromPairs returns a slice of SecureCookie instances.
+//
+// It is a convenience function to create a list of codecs for key rotation. Note
+// that the generated Codecs will have the default options applied: callers
+// should iterate over each Codec and type-assert the underlying *SecureCookie to
+// change these.
+//
+// Example:
+//
+//      codecs := securecookie.CodecsFromPairs(
+//           []byte("new-hash-key"),
+//           []byte("new-block-key"),
+//           []byte("old-hash-key"),
+//           []byte("old-block-key"),
+//       )
+//
+//      // Modify each instance.
+//      for _, s := range codecs {
+//             if cookie, ok := s.(*securecookie.SecureCookie); ok {
+//                 cookie.MaxAge(86400 * 7)
+//                 cookie.SetSerializer(securecookie.JSONEncoder{})
+//                 cookie.HashFunc(sha512.New512_256)
+//             }
+//         }
+//
+func CodecsFromPairs(keyPairs ...[]byte) []Codec {
+	codecs := make([]Codec, len(keyPairs)/2+len(keyPairs)%2)
+	for i := 0; i < len(keyPairs); i += 2 {
+		var blockKey []byte
+		if i+1 < len(keyPairs) {
+			blockKey = keyPairs[i+1]
+		}
+		codecs[i/2] = New(keyPairs[i], blockKey)
+	}
+	return codecs
+}
+
+// EncodeMulti encodes a cookie value using a group of codecs.
+//
+// The codecs are tried in order. Multiple codecs are accepted to allow
+// key rotation.
+//
+// On error, may return a MultiError.
+func EncodeMulti(name string, value interface{}, codecs ...Codec) (string, error) {
+	if len(codecs) == 0 {
+		return "", errNoCodecs
+	}
+
+	var errors MultiError
+	for _, codec := range codecs {
+		encoded, err := codec.Encode(name, value)
+		if err == nil {
+			return encoded, nil
+		}
+		errors = append(errors, err)
+	}
+	return "", errors
+}
+
+// DecodeMulti decodes a cookie value using a group of codecs.
+//
+// The codecs are tried in order. Multiple codecs are accepted to allow
+// key rotation.
+//
+// On error, may return a MultiError.
+func DecodeMulti(name string, value string, dst interface{}, codecs ...Codec) error {
+	if len(codecs) == 0 {
+		return errNoCodecs
+	}
+
+	var errors MultiError
+	for _, codec := range codecs {
+		err := codec.Decode(name, value, dst)
+		if err == nil {
+			return nil
+		}
+		errors = append(errors, err)
+	}
+	return errors
+}
+
+// MultiError groups multiple errors.
+type MultiError []error
+
+func (m MultiError) IsUsage() bool    { return m.any(func(e Error) bool { return e.IsUsage() }) }
+func (m MultiError) IsDecode() bool   { return m.any(func(e Error) bool { return e.IsDecode() }) }
+func (m MultiError) IsInternal() bool { return m.any(func(e Error) bool { return e.IsInternal() }) }
+
+// Cause returns nil for MultiError; there is no unique underlying cause in the
+// general case.
+//
+// Note: we could conceivably return a non-nil Cause only when there is exactly
+// one child error with a Cause.  However, it would be brittle for client code
+// to rely on the arity of causes inside a MultiError, so we have opted not to
+// provide this functionality.  Clients which really wish to access the Causes
+// of the underlying errors are free to iterate through the errors themselves.
+func (m MultiError) Cause() error { return nil }
+
+func (m MultiError) Error() string {
+	s, n := "", 0
+	for _, e := range m {
+		if e != nil {
+			if n == 0 {
+				s = e.Error()
+			}
+			n++
+		}
+	}
+	switch n {
+	case 0:
+		return "(0 errors)"
+	case 1:
+		return s
+	case 2:
+		return s + " (and 1 other error)"
+	}
+	return fmt.Sprintf("%s (and %d other errors)", s, n-1)
+}
+
+// any returns true if any element of m is an Error for which pred returns true.
+func (m MultiError) any(pred func(Error) bool) bool {
+	for _, e := range m {
+		if ourErr, ok := e.(Error); ok && pred(ourErr) {
+			return true
+		}
+	}
+	return false
+}

+ 43 - 0
vendor/github.com/gorilla/sessions/AUTHORS

@@ -0,0 +1,43 @@
+# This is the official list of gorilla/sessions authors for copyright purposes.
+#
+# Please keep the list sorted.
+
+Ahmadreza Zibaei <ahmadrezazibaei@hotmail.com>
+Anton Lindström <lindztr@gmail.com>
+Brian Jones <mojobojo@gmail.com>
+Collin Stedman <kronion@users.noreply.github.com>
+Deniz Eren <dee.116@gmail.com>
+Dmitry Chestnykh <dmitry@codingrobots.com>
+Dustin Oprea <myselfasunder@gmail.com>
+Egon Elbre <egonelbre@gmail.com>
+enumappstore <appstore@enumapps.com>
+Geofrey Ernest <geofreyernest@live.com>
+Google LLC (https://opensource.google.com/)
+Jerry Saravia <SaraviaJ@gmail.com>
+Jonathan Gillham <jonathan.gillham@gamil.com>
+Justin Clift <justin@postgresql.org>
+Justin Hellings <justin.hellings@gmail.com>
+Kamil Kisiel <kamil@kamilkisiel.net>
+Keiji Yoshida <yoshida.keiji.84@gmail.com>
+kliron <kliron@gmail.com>
+Kshitij Saraogi <KshitijSaraogi@gmail.com>
+Lauris BH <lauris@nix.lv>
+Lukas Rist <glaslos@gmail.com>
+Mark Dain <ancarda@users.noreply.github.com>
+Matt Ho <matt.ho@gmail.com>
+Matt Silverlock <matt@eatsleeprepeat.net>
+Mattias Wadman <mattias.wadman@gmail.com>
+Michael Schuett <michaeljs1990@gmail.com>
+Michael Stapelberg <stapelberg@users.noreply.github.com>
+Mirco Zeiss <mirco.zeiss@gmail.com>
+moraes <rodrigo.moraes@gmail.com>
+nvcnvn <nguyen@open-vn.org>
+pappz <zoltan.pmail@gmail.com>
+Pontus Leitzler <leitzler@users.noreply.github.com>
+QuaSoft <info@quasoft.net>
+rcadena <robert.cadena@gmail.com>
+rodrigo moraes <rodrigo.moraes@gmail.com>
+Shawn Smith <shawnpsmith@gmail.com>
+Taylor Hurt <taylor.a.hurt@gmail.com>
+Tortuoise <sanyasinp@gmail.com>
+Vitor De Mario <vitordemario@gmail.com>

+ 27 - 0
vendor/github.com/gorilla/sessions/LICENSE

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

+ 95 - 0
vendor/github.com/gorilla/sessions/README.md

@@ -0,0 +1,95 @@
+# sessions
+
+[![GoDoc](https://godoc.org/github.com/gorilla/sessions?status.svg)](https://godoc.org/github.com/gorilla/sessions) [![Build Status](https://travis-ci.org/gorilla/sessions.svg?branch=master)](https://travis-ci.org/gorilla/sessions)
+[![Sourcegraph](https://sourcegraph.com/github.com/gorilla/sessions/-/badge.svg)](https://sourcegraph.com/github.com/gorilla/sessions?badge)
+
+gorilla/sessions provides cookie and filesystem sessions and infrastructure for
+custom session backends.
+
+The key features are:
+
+- Simple API: use it as an easy way to set signed (and optionally
+  encrypted) cookies.
+- Built-in backends to store sessions in cookies or the filesystem.
+- Flash messages: session values that last until read.
+- Convenient way to switch session persistency (aka "remember me") and set
+  other attributes.
+- Mechanism to rotate authentication and encryption keys.
+- Multiple sessions per request, even using different backends.
+- Interfaces and infrastructure for custom session backends: sessions from
+  different stores can be retrieved and batch-saved using a common API.
+
+Let's start with an example that shows the sessions API in a nutshell:
+
+```go
+	import (
+		"net/http"
+		"github.com/gorilla/sessions"
+	)
+
+	// Note: Don't store your key in your source code. Pass it via an
+	// environmental variable, or flag (or both), and don't accidentally commit it
+	// alongside your code. Ensure your key is sufficiently random - i.e. use Go's
+	// crypto/rand or securecookie.GenerateRandomKey(32) and persist the result.
+	var store = sessions.NewCookieStore(os.Getenv("SESSION_KEY"))
+
+	func MyHandler(w http.ResponseWriter, r *http.Request) {
+		// Get a session. We're ignoring the error resulted from decoding an
+		// existing session: Get() always returns a session, even if empty.
+		session, _ := store.Get(r, "session-name")
+		// Set some session values.
+		session.Values["foo"] = "bar"
+		session.Values[42] = 43
+		// Save it before we write to the response/return from the handler.
+		session.Save(r, w)
+	}
+```
+
+First we initialize a session store calling `NewCookieStore()` and passing a
+secret key used to authenticate the session. Inside the handler, we call
+`store.Get()` to retrieve an existing session or create a new one. Then we set
+some session values in session.Values, which is a `map[interface{}]interface{}`.
+And finally we call `session.Save()` to save the session in the response.
+
+Important Note: If you aren't using gorilla/mux, you need to wrap your handlers
+with
+[`context.ClearHandler`](http://www.gorillatoolkit.org/pkg/context#ClearHandler)
+or else you will leak memory! An easy way to do this is to wrap the top-level
+mux when calling http.ListenAndServe:
+
+```go
+	http.ListenAndServe(":8080", context.ClearHandler(http.DefaultServeMux))
+```
+
+The ClearHandler function is provided by the gorilla/context package.
+
+More examples are available [on the Gorilla
+website](http://www.gorillatoolkit.org/pkg/sessions).
+
+## Store Implementations
+
+Other implementations of the `sessions.Store` interface:
+
+- [github.com/starJammer/gorilla-sessions-arangodb](https://github.com/starJammer/gorilla-sessions-arangodb) - ArangoDB
+- [github.com/yosssi/boltstore](https://github.com/yosssi/boltstore) - Bolt
+- [github.com/srinathgs/couchbasestore](https://github.com/srinathgs/couchbasestore) - Couchbase
+- [github.com/denizeren/dynamostore](https://github.com/denizeren/dynamostore) - Dynamodb on AWS
+- [github.com/savaki/dynastore](https://github.com/savaki/dynastore) - DynamoDB on AWS (Official AWS library)
+- [github.com/bradleypeabody/gorilla-sessions-memcache](https://github.com/bradleypeabody/gorilla-sessions-memcache) - Memcache
+- [github.com/dsoprea/go-appengine-sessioncascade](https://github.com/dsoprea/go-appengine-sessioncascade) - Memcache/Datastore/Context in AppEngine
+- [github.com/kidstuff/mongostore](https://github.com/kidstuff/mongostore) - MongoDB
+- [github.com/srinathgs/mysqlstore](https://github.com/srinathgs/mysqlstore) - MySQL
+- [github.com/EnumApps/clustersqlstore](https://github.com/EnumApps/clustersqlstore) - MySQL Cluster
+- [github.com/antonlindstrom/pgstore](https://github.com/antonlindstrom/pgstore) - PostgreSQL
+- [github.com/boj/redistore](https://github.com/boj/redistore) - Redis
+- [github.com/boj/rethinkstore](https://github.com/boj/rethinkstore) - RethinkDB
+- [github.com/boj/riakstore](https://github.com/boj/riakstore) - Riak
+- [github.com/michaeljs1990/sqlitestore](https://github.com/michaeljs1990/sqlitestore) - SQLite
+- [github.com/wader/gormstore](https://github.com/wader/gormstore) - GORM (MySQL, PostgreSQL, SQLite)
+- [github.com/gernest/qlstore](https://github.com/gernest/qlstore) - ql
+- [github.com/quasoft/memstore](https://github.com/quasoft/memstore) - In-memory implementation for use in unit tests
+- [github.com/lafriks/xormstore](https://github.com/lafriks/xormstore) - XORM (MySQL, PostgreSQL, SQLite, Microsoft SQL Server, TiDB)
+
+## License
+
+BSD licensed. See the LICENSE file for details.

+ 202 - 0
vendor/github.com/gorilla/sessions/doc.go

@@ -0,0 +1,202 @@
+// Copyright 2012 The Gorilla Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Package sessions provides cookie and filesystem sessions and
+infrastructure for custom session backends.
+
+The key features are:
+
+	* Simple API: use it as an easy way to set signed (and optionally
+	  encrypted) cookies.
+	* Built-in backends to store sessions in cookies or the filesystem.
+	* Flash messages: session values that last until read.
+	* Convenient way to switch session persistency (aka "remember me") and set
+	  other attributes.
+	* Mechanism to rotate authentication and encryption keys.
+	* Multiple sessions per request, even using different backends.
+	* Interfaces and infrastructure for custom session backends: sessions from
+	  different stores can be retrieved and batch-saved using a common API.
+
+Let's start with an example that shows the sessions API in a nutshell:
+
+	import (
+		"net/http"
+		"github.com/gorilla/sessions"
+	)
+
+	// Note: Don't store your key in your source code. Pass it via an
+	// environmental variable, or flag (or both), and don't accidentally commit it
+	// alongside your code. Ensure your key is sufficiently random - i.e. use Go's
+	// crypto/rand or securecookie.GenerateRandomKey(32) and persist the result.
+	var store = sessions.NewCookieStore(os.Getenv("SESSION_KEY"))
+
+	func MyHandler(w http.ResponseWriter, r *http.Request) {
+		// Get a session. Get() always returns a session, even if empty.
+		session, err := store.Get(r, "session-name")
+		if err != nil {
+			http.Error(w, err.Error(), http.StatusInternalServerError)
+			return
+		}
+
+		// Set some session values.
+		session.Values["foo"] = "bar"
+		session.Values[42] = 43
+		// Save it before we write to the response/return from the handler.
+		session.Save(r, w)
+	}
+
+First we initialize a session store calling NewCookieStore() and passing a
+secret key used to authenticate the session. Inside the handler, we call
+store.Get() to retrieve an existing session or a new one. Then we set some
+session values in session.Values, which is a map[interface{}]interface{}.
+And finally we call session.Save() to save the session in the response.
+
+Note that in production code, we should check for errors when calling
+session.Save(r, w), and either display an error message or otherwise handle it.
+
+Save must be called before writing to the response, otherwise the session
+cookie will not be sent to the client.
+
+Important Note: If you aren't using gorilla/mux, you need to wrap your handlers
+with context.ClearHandler as or else you will leak memory! An easy way to do this
+is to wrap the top-level mux when calling http.ListenAndServe:
+
+    http.ListenAndServe(":8080", context.ClearHandler(http.DefaultServeMux))
+
+The ClearHandler function is provided by the gorilla/context package.
+
+That's all you need to know for the basic usage. Let's take a look at other
+options, starting with flash messages.
+
+Flash messages are session values that last until read. The term appeared with
+Ruby On Rails a few years back. When we request a flash message, it is removed
+from the session. To add a flash, call session.AddFlash(), and to get all
+flashes, call session.Flashes(). Here is an example:
+
+	func MyHandler(w http.ResponseWriter, r *http.Request) {
+		// Get a session.
+		session, err := store.Get(r, "session-name")
+		if err != nil {
+			http.Error(w, err.Error(), http.StatusInternalServerError)
+			return
+		}
+
+		// Get the previous flashes, if any.
+		if flashes := session.Flashes(); len(flashes) > 0 {
+			// Use the flash values.
+		} else {
+			// Set a new flash.
+			session.AddFlash("Hello, flash messages world!")
+		}
+		session.Save(r, w)
+	}
+
+Flash messages are useful to set information to be read after a redirection,
+like after form submissions.
+
+There may also be cases where you want to store a complex datatype within a
+session, such as a struct. Sessions are serialised using the encoding/gob package,
+so it is easy to register new datatypes for storage in sessions:
+
+	import(
+		"encoding/gob"
+		"github.com/gorilla/sessions"
+	)
+
+	type Person struct {
+		FirstName	string
+		LastName 	string
+		Email		string
+		Age			int
+	}
+
+	type M map[string]interface{}
+
+	func init() {
+
+		gob.Register(&Person{})
+		gob.Register(&M{})
+	}
+
+As it's not possible to pass a raw type as a parameter to a function, gob.Register()
+relies on us passing it a value of the desired type. In the example above we've passed
+it a pointer to a struct and a pointer to a custom type representing a
+map[string]interface. (We could have passed non-pointer values if we wished.) This will
+then allow us to serialise/deserialise values of those types to and from our sessions.
+
+Note that because session values are stored in a map[string]interface{}, there's
+a need to type-assert data when retrieving it. We'll use the Person struct we registered above:
+
+	func MyHandler(w http.ResponseWriter, r *http.Request) {
+		session, err := store.Get(r, "session-name")
+		if err != nil {
+			http.Error(w, err.Error(), http.StatusInternalServerError)
+			return
+		}
+
+		// Retrieve our struct and type-assert it
+		val := session.Values["person"]
+		var person = &Person{}
+		if person, ok := val.(*Person); !ok {
+			// Handle the case that it's not an expected type
+		}
+
+		// Now we can use our person object
+	}
+
+By default, session cookies last for a month. This is probably too long for
+some cases, but it is easy to change this and other attributes during
+runtime. Sessions can be configured individually or the store can be
+configured and then all sessions saved using it will use that configuration.
+We access session.Options or store.Options to set a new configuration. The
+fields are basically a subset of http.Cookie fields. Let's change the
+maximum age of a session to one week:
+
+	session.Options = &sessions.Options{
+		Path:     "/",
+		MaxAge:   86400 * 7,
+		HttpOnly: true,
+	}
+
+Sometimes we may want to change authentication and/or encryption keys without
+breaking existing sessions. The CookieStore supports key rotation, and to use
+it you just need to set multiple authentication and encryption keys, in pairs,
+to be tested in order:
+
+	var store = sessions.NewCookieStore(
+		[]byte("new-authentication-key"),
+		[]byte("new-encryption-key"),
+		[]byte("old-authentication-key"),
+		[]byte("old-encryption-key"),
+	)
+
+New sessions will be saved using the first pair. Old sessions can still be
+read because the first pair will fail, and the second will be tested. This
+makes it easy to "rotate" secret keys and still be able to validate existing
+sessions. Note: for all pairs the encryption key is optional; set it to nil
+or omit it and and encryption won't be used.
+
+Multiple sessions can be used in the same request, even with different
+session backends. When this happens, calling Save() on each session
+individually would be cumbersome, so we have a way to save all sessions
+at once: it's sessions.Save(). Here's an example:
+
+	var store = sessions.NewCookieStore([]byte("something-very-secret"))
+
+	func MyHandler(w http.ResponseWriter, r *http.Request) {
+		// Get a session and set a value.
+		session1, _ := store.Get(r, "session-one")
+		session1.Values["foo"] = "bar"
+		// Get another session and set another value.
+		session2, _ := store.Get(r, "session-two")
+		session2.Values[42] = 43
+		// Save all sessions.
+		sessions.Save(r, w)
+	}
+
+This is possible because when we call Get() from a session store, it adds the
+session to a common registry. Save() uses it to save all registered sessions.
+*/
+package sessions

+ 6 - 0
vendor/github.com/gorilla/sessions/go.mod

@@ -0,0 +1,6 @@
+module "github.com/gorilla/sessions"
+
+require (
+	"github.com/gorilla/context" v1.1.1
+	"github.com/gorilla/securecookie" v1.1.1
+)

+ 102 - 0
vendor/github.com/gorilla/sessions/lex.go

@@ -0,0 +1,102 @@
+// This file contains code adapted from the Go standard library
+// https://github.com/golang/go/blob/39ad0fd0789872f9469167be7fe9578625ff246e/src/net/http/lex.go
+
+package sessions
+
+import "strings"
+
+var isTokenTable = [127]bool{
+	'!':  true,
+	'#':  true,
+	'$':  true,
+	'%':  true,
+	'&':  true,
+	'\'': true,
+	'*':  true,
+	'+':  true,
+	'-':  true,
+	'.':  true,
+	'0':  true,
+	'1':  true,
+	'2':  true,
+	'3':  true,
+	'4':  true,
+	'5':  true,
+	'6':  true,
+	'7':  true,
+	'8':  true,
+	'9':  true,
+	'A':  true,
+	'B':  true,
+	'C':  true,
+	'D':  true,
+	'E':  true,
+	'F':  true,
+	'G':  true,
+	'H':  true,
+	'I':  true,
+	'J':  true,
+	'K':  true,
+	'L':  true,
+	'M':  true,
+	'N':  true,
+	'O':  true,
+	'P':  true,
+	'Q':  true,
+	'R':  true,
+	'S':  true,
+	'T':  true,
+	'U':  true,
+	'W':  true,
+	'V':  true,
+	'X':  true,
+	'Y':  true,
+	'Z':  true,
+	'^':  true,
+	'_':  true,
+	'`':  true,
+	'a':  true,
+	'b':  true,
+	'c':  true,
+	'd':  true,
+	'e':  true,
+	'f':  true,
+	'g':  true,
+	'h':  true,
+	'i':  true,
+	'j':  true,
+	'k':  true,
+	'l':  true,
+	'm':  true,
+	'n':  true,
+	'o':  true,
+	'p':  true,
+	'q':  true,
+	'r':  true,
+	's':  true,
+	't':  true,
+	'u':  true,
+	'v':  true,
+	'w':  true,
+	'x':  true,
+	'y':  true,
+	'z':  true,
+	'|':  true,
+	'~':  true,
+}
+
+func isToken(r rune) bool {
+	i := int(r)
+	return i < len(isTokenTable) && isTokenTable[i]
+}
+
+func isNotToken(r rune) bool {
+	return !isToken(r)
+}
+
+func isCookieNameValid(raw string) bool {
+	if raw == "" {
+		return false
+	}
+	return strings.IndexFunc(raw, isNotToken) < 0
+}

+ 18 - 0
vendor/github.com/gorilla/sessions/options.go

@@ -0,0 +1,18 @@
+// +build !go1.11
+
+package sessions
+
+// Options stores configuration for a session or session store.
+//
+// Fields are a subset of http.Cookie fields.
+type Options struct {
+	Path   string
+	Domain string
+	// MaxAge=0 means no Max-Age attribute specified and the cookie will be
+	// deleted after the browser session ends.
+	// MaxAge<0 means delete cookie immediately.
+	// MaxAge>0 means Max-Age attribute present and given in seconds.
+	MaxAge   int
+	Secure   bool
+	HttpOnly bool
+}

+ 22 - 0
vendor/github.com/gorilla/sessions/options_go111.go

@@ -0,0 +1,22 @@
+// +build go1.11
+
+package sessions
+
+import "net/http"
+
+// Options stores configuration for a session or session store.
+//
+// Fields are a subset of http.Cookie fields.
+type Options struct {
+	Path   string
+	Domain string
+	// MaxAge=0 means no Max-Age attribute specified and the cookie will be
+	// deleted after the browser session ends.
+	// MaxAge<0 means delete cookie immediately.
+	// MaxAge>0 means Max-Age attribute present and given in seconds.
+	MaxAge   int
+	Secure   bool
+	HttpOnly bool
+	// Defaults to http.SameSiteDefaultMode
+	SameSite http.SameSite
+}

+ 226 - 0
vendor/github.com/gorilla/sessions/sessions.go

@@ -0,0 +1,226 @@
+// Copyright 2012 The Gorilla Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sessions
+
+import (
+	"encoding/gob"
+	"fmt"
+	"net/http"
+	"time"
+
+	"github.com/gorilla/context"
+)
+
+// Default flashes key.
+const flashesKey = "_flash"
+
+// Session --------------------------------------------------------------------
+
+// NewSession is called by session stores to create a new session instance.
+func NewSession(store Store, name string) *Session {
+	return &Session{
+		Values:  make(map[interface{}]interface{}),
+		store:   store,
+		name:    name,
+		Options: new(Options),
+	}
+}
+
+// Session stores the values and optional configuration for a session.
+type Session struct {
+	// The ID of the session, generated by stores. It should not be used for
+	// user data.
+	ID string
+	// Values contains the user-data for the session.
+	Values  map[interface{}]interface{}
+	Options *Options
+	IsNew   bool
+	store   Store
+	name    string
+}
+
+// Flashes returns a slice of flash messages from the session.
+//
+// A single variadic argument is accepted, and it is optional: it defines
+// the flash key. If not defined "_flash" is used by default.
+func (s *Session) Flashes(vars ...string) []interface{} {
+	var flashes []interface{}
+	key := flashesKey
+	if len(vars) > 0 {
+		key = vars[0]
+	}
+	if v, ok := s.Values[key]; ok {
+		// Drop the flashes and return it.
+		delete(s.Values, key)
+		flashes = v.([]interface{})
+	}
+	return flashes
+}
+
+// AddFlash adds a flash message to the session.
+//
+// A single variadic argument is accepted, and it is optional: it defines
+// the flash key. If not defined "_flash" is used by default.
+func (s *Session) AddFlash(value interface{}, vars ...string) {
+	key := flashesKey
+	if len(vars) > 0 {
+		key = vars[0]
+	}
+	var flashes []interface{}
+	if v, ok := s.Values[key]; ok {
+		flashes = v.([]interface{})
+	}
+	s.Values[key] = append(flashes, value)
+}
+
+// Save is a convenience method to save this session. It is the same as calling
+// store.Save(request, response, session). You should call Save before writing to
+// the response or returning from the handler.
+func (s *Session) Save(r *http.Request, w http.ResponseWriter) error {
+	return s.store.Save(r, w, s)
+}
+
+// Name returns the name used to register the session.
+func (s *Session) Name() string {
+	return s.name
+}
+
+// Store returns the session store used to register the session.
+func (s *Session) Store() Store {
+	return s.store
+}
+
+// Registry -------------------------------------------------------------------
+
+// sessionInfo stores a session tracked by the registry.
+type sessionInfo struct {
+	s *Session
+	e error
+}
+
+// contextKey is the type used to store the registry in the context.
+type contextKey int
+
+// registryKey is the key used to store the registry in the context.
+const registryKey contextKey = 0
+
+// GetRegistry returns a registry instance for the current request.
+func GetRegistry(r *http.Request) *Registry {
+	registry := context.Get(r, registryKey)
+	if registry != nil {
+		return registry.(*Registry)
+	}
+	newRegistry := &Registry{
+		request:  r,
+		sessions: make(map[string]sessionInfo),
+	}
+	context.Set(r, registryKey, newRegistry)
+	return newRegistry
+}
+
+// Registry stores sessions used during a request.
+type Registry struct {
+	request  *http.Request
+	sessions map[string]sessionInfo
+}
+
+// Get registers and returns a session for the given name and session store.
+//
+// It returns a new session if there are no sessions registered for the name.
+func (s *Registry) Get(store Store, name string) (session *Session, err error) {
+	if !isCookieNameValid(name) {
+		return nil, fmt.Errorf("sessions: invalid character in cookie name: %s", name)
+	}
+	if info, ok := s.sessions[name]; ok {
+		session, err = info.s, info.e
+	} else {
+		session, err = store.New(s.request, name)
+		session.name = name
+		s.sessions[name] = sessionInfo{s: session, e: err}
+	}
+	session.store = store
+	return
+}
+
+// Save saves all sessions registered for the current request.
+func (s *Registry) Save(w http.ResponseWriter) error {
+	var errMulti MultiError
+	for name, info := range s.sessions {
+		session := info.s
+		if session.store == nil {
+			errMulti = append(errMulti, fmt.Errorf(
+				"sessions: missing store for session %q", name))
+		} else if err := session.store.Save(s.request, w, session); err != nil {
+			errMulti = append(errMulti, fmt.Errorf(
+				"sessions: error saving session %q -- %v", name, err))
+		}
+	}
+	if errMulti != nil {
+		return errMulti
+	}
+	return nil
+}
+
+// Helpers --------------------------------------------------------------------
+
+func init() {
+	gob.Register([]interface{}{})
+}
+
+// Save saves all sessions used during the current request.
+func Save(r *http.Request, w http.ResponseWriter) error {
+	return GetRegistry(r).Save(w)
+}
+
+// NewCookie returns an http.Cookie with the options set. It also sets
+// the Expires field calculated based on the MaxAge value, for Internet
+// Explorer compatibility.
+func NewCookie(name, value string, options *Options) *http.Cookie {
+	cookie := &http.Cookie{
+		Name:     name,
+		Value:    value,
+		Path:     options.Path,
+		Domain:   options.Domain,
+		MaxAge:   options.MaxAge,
+		Secure:   options.Secure,
+		HttpOnly: options.HttpOnly,
+	}
+	if options.MaxAge > 0 {
+		d := time.Duration(options.MaxAge) * time.Second
+		cookie.Expires = time.Now().Add(d)
+	} else if options.MaxAge < 0 {
+		// Set it to the past to expire now.
+		cookie.Expires = time.Unix(1, 0)
+	}
+	return cookie
+}
+
+// Error ----------------------------------------------------------------------
+
+// MultiError stores multiple errors.
+//
+// Borrowed from the App Engine SDK.
+type MultiError []error
+
+func (m MultiError) Error() string {
+	s, n := "", 0
+	for _, e := range m {
+		if e != nil {
+			if n == 0 {
+				s = e.Error()
+			}
+			n++
+		}
+	}
+	switch n {
+	case 0:
+		return "(0 errors)"
+	case 1:
+		return s
+	case 2:
+		return s + " (and 1 other error)"
+	}
+	return fmt.Sprintf("%s (and %d other errors)", s, n-1)
+}

+ 292 - 0
vendor/github.com/gorilla/sessions/store.go

@@ -0,0 +1,292 @@
+// Copyright 2012 The Gorilla Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sessions
+
+import (
+	"encoding/base32"
+	"io/ioutil"
+	"net/http"
+	"os"
+	"path/filepath"
+	"strings"
+	"sync"
+
+	"github.com/gorilla/securecookie"
+)
+
+// Store is an interface for custom session stores.
+//
+// See CookieStore and FilesystemStore for examples.
+type Store interface {
+	// Get should return a cached session.
+	Get(r *http.Request, name string) (*Session, error)
+
+	// New should create and return a new session.
+	//
+	// Note that New should never return a nil session, even in the case of
+	// an error if using the Registry infrastructure to cache the session.
+	New(r *http.Request, name string) (*Session, error)
+
+	// Save should persist session to the underlying store implementation.
+	Save(r *http.Request, w http.ResponseWriter, s *Session) error
+}
+
+// CookieStore ----------------------------------------------------------------
+
+// NewCookieStore returns a new CookieStore.
+//
+// Keys are defined in pairs to allow key rotation, but the common case is
+// to set a single authentication key and optionally an encryption key.
+//
+// The first key in a pair is used for authentication and the second for
+// encryption. The encryption key can be set to nil or omitted in the last
+// pair, but the authentication key is required in all pairs.
+//
+// It is recommended to use an authentication key with 32 or 64 bytes.
+// The encryption key, if set, must be either 16, 24, or 32 bytes to select
+// AES-128, AES-192, or AES-256 modes.
+func NewCookieStore(keyPairs ...[]byte) *CookieStore {
+	cs := &CookieStore{
+		Codecs: securecookie.CodecsFromPairs(keyPairs...),
+		Options: &Options{
+			Path:   "/",
+			MaxAge: 86400 * 30,
+		},
+	}
+
+	cs.MaxAge(cs.Options.MaxAge)
+	return cs
+}
+
+// CookieStore stores sessions using secure cookies.
+type CookieStore struct {
+	Codecs  []securecookie.Codec
+	Options *Options // default configuration
+}
+
+// Get returns a session for the given name after adding it to the registry.
+//
+// It returns a new session if the sessions doesn't exist. Access IsNew on
+// the session to check if it is an existing session or a new one.
+//
+// It returns a new session and an error if the session exists but could
+// not be decoded.
+func (s *CookieStore) Get(r *http.Request, name string) (*Session, error) {
+	return GetRegistry(r).Get(s, name)
+}
+
+// New returns a session for the given name without adding it to the registry.
+//
+// The difference between New() and Get() is that calling New() twice will
+// decode the session data twice, while Get() registers and reuses the same
+// decoded session after the first call.
+func (s *CookieStore) New(r *http.Request, name string) (*Session, error) {
+	session := NewSession(s, name)
+	opts := *s.Options
+	session.Options = &opts
+	session.IsNew = true
+	var err error
+	if c, errCookie := r.Cookie(name); errCookie == nil {
+		err = securecookie.DecodeMulti(name, c.Value, &session.Values,
+			s.Codecs...)
+		if err == nil {
+			session.IsNew = false
+		}
+	}
+	return session, err
+}
+
+// Save adds a single session to the response.
+func (s *CookieStore) Save(r *http.Request, w http.ResponseWriter,
+	session *Session) error {
+	encoded, err := securecookie.EncodeMulti(session.Name(), session.Values,
+		s.Codecs...)
+	if err != nil {
+		return err
+	}
+	http.SetCookie(w, NewCookie(session.Name(), encoded, session.Options))
+	return nil
+}
+
+// MaxAge sets the maximum age for the store and the underlying cookie
+// implementation. Individual sessions can be deleted by setting Options.MaxAge
+// = -1 for that session.
+func (s *CookieStore) MaxAge(age int) {
+	s.Options.MaxAge = age
+
+	// Set the maxAge for each securecookie instance.
+	for _, codec := range s.Codecs {
+		if sc, ok := codec.(*securecookie.SecureCookie); ok {
+			sc.MaxAge(age)
+		}
+	}
+}
+
+// FilesystemStore ------------------------------------------------------------
+
+var fileMutex sync.RWMutex
+
+// NewFilesystemStore returns a new FilesystemStore.
+//
+// The path argument is the directory where sessions will be saved. If empty
+// it will use os.TempDir().
+//
+// See NewCookieStore() for a description of the other parameters.
+func NewFilesystemStore(path string, keyPairs ...[]byte) *FilesystemStore {
+	if path == "" {
+		path = os.TempDir()
+	}
+	fs := &FilesystemStore{
+		Codecs: securecookie.CodecsFromPairs(keyPairs...),
+		Options: &Options{
+			Path:   "/",
+			MaxAge: 86400 * 30,
+		},
+		path: path,
+	}
+
+	fs.MaxAge(fs.Options.MaxAge)
+	return fs
+}
+
+// FilesystemStore stores sessions in the filesystem.
+//
+// It also serves as a reference for custom stores.
+//
+// This store is still experimental and not well tested. Feedback is welcome.
+type FilesystemStore struct {
+	Codecs  []securecookie.Codec
+	Options *Options // default configuration
+	path    string
+}
+
+// MaxLength restricts the maximum length of new sessions to l.
+// If l is 0 there is no limit to the size of a session, use with caution.
+// The default for a new FilesystemStore is 4096.
+func (s *FilesystemStore) MaxLength(l int) {
+	for _, c := range s.Codecs {
+		if codec, ok := c.(*securecookie.SecureCookie); ok {
+			codec.MaxLength(l)
+		}
+	}
+}
+
+// Get returns a session for the given name after adding it to the registry.
+//
+// See CookieStore.Get().
+func (s *FilesystemStore) Get(r *http.Request, name string) (*Session, error) {
+	return GetRegistry(r).Get(s, name)
+}
+
+// New returns a session for the given name without adding it to the registry.
+//
+// See CookieStore.New().
+func (s *FilesystemStore) New(r *http.Request, name string) (*Session, error) {
+	session := NewSession(s, name)
+	opts := *s.Options
+	session.Options = &opts
+	session.IsNew = true
+	var err error
+	if c, errCookie := r.Cookie(name); errCookie == nil {
+		err = securecookie.DecodeMulti(name, c.Value, &session.ID, s.Codecs...)
+		if err == nil {
+			err = s.load(session)
+			if err == nil {
+				session.IsNew = false
+			}
+		}
+	}
+	return session, err
+}
+
+// Save adds a single session to the response.
+//
+// If the Options.MaxAge of the session is <= 0 then the session file will be
+// deleted from the store path. With this process it enforces the properly
+// session cookie handling so no need to trust in the cookie management in the
+// web browser.
+func (s *FilesystemStore) Save(r *http.Request, w http.ResponseWriter,
+	session *Session) error {
+	// Delete if max-age is <= 0
+	if session.Options.MaxAge <= 0 {
+		if err := s.erase(session); err != nil {
+			return err
+		}
+		http.SetCookie(w, NewCookie(session.Name(), "", session.Options))
+		return nil
+	}
+
+	if session.ID == "" {
+		// Because the ID is used in the filename, encode it to
+		// use alphanumeric characters only.
+		session.ID = strings.TrimRight(
+			base32.StdEncoding.EncodeToString(
+				securecookie.GenerateRandomKey(32)), "=")
+	}
+	if err := s.save(session); err != nil {
+		return err
+	}
+	encoded, err := securecookie.EncodeMulti(session.Name(), session.ID,
+		s.Codecs...)
+	if err != nil {
+		return err
+	}
+	http.SetCookie(w, NewCookie(session.Name(), encoded, session.Options))
+	return nil
+}
+
+// MaxAge sets the maximum age for the store and the underlying cookie
+// implementation. Individual sessions can be deleted by setting Options.MaxAge
+// = -1 for that session.
+func (s *FilesystemStore) MaxAge(age int) {
+	s.Options.MaxAge = age
+
+	// Set the maxAge for each securecookie instance.
+	for _, codec := range s.Codecs {
+		if sc, ok := codec.(*securecookie.SecureCookie); ok {
+			sc.MaxAge(age)
+		}
+	}
+}
+
+// save writes encoded session.Values to a file.
+func (s *FilesystemStore) save(session *Session) error {
+	encoded, err := securecookie.EncodeMulti(session.Name(), session.Values,
+		s.Codecs...)
+	if err != nil {
+		return err
+	}
+	filename := filepath.Join(s.path, "session_"+session.ID)
+	fileMutex.Lock()
+	defer fileMutex.Unlock()
+	return ioutil.WriteFile(filename, []byte(encoded), 0600)
+}
+
+// load reads a file and decodes its content into session.Values.
+func (s *FilesystemStore) load(session *Session) error {
+	filename := filepath.Join(s.path, "session_"+session.ID)
+	fileMutex.RLock()
+	defer fileMutex.RUnlock()
+	fdata, err := ioutil.ReadFile(filename)
+	if err != nil {
+		return err
+	}
+	if err = securecookie.DecodeMulti(session.Name(), string(fdata),
+		&session.Values, s.Codecs...); err != nil {
+		return err
+	}
+	return nil
+}
+
+// delete session file
+func (s *FilesystemStore) erase(session *Session) error {
+	filename := filepath.Join(s.path, "session_"+session.ID)
+
+	fileMutex.RLock()
+	defer fileMutex.RUnlock()
+
+	err := os.Remove(filename)
+	return err
+}

+ 20 - 0
vendor/github.com/martini-contrib/sessions/LICENSE

@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2013 Jeremy Saenz
+
+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.

+ 41 - 0
vendor/github.com/martini-contrib/sessions/README.md

@@ -0,0 +1,41 @@
+# sessions [![wercker status](https://app.wercker.com/status/af92c7633124fffea8984e48ee0c418b "wercker status")](https://app.wercker.com/project/bykey/af92c7633124fffea8984e48ee0c418b)
+Martini middleware/handler for easy session management.
+
+[API Reference](http://godoc.org/github.com/martini-contrib/sessions)
+
+## Usage
+
+~~~ go
+package main
+
+import (
+  "github.com/go-martini/martini"
+  "github.com/martini-contrib/sessions"
+)
+
+func main() {
+	m := martini.Classic()
+
+	store := sessions.NewCookieStore([]byte("secret123"))
+	m.Use(sessions.Sessions("my_session", store))
+
+	m.Get("/set", func(session sessions.Session) string {
+		session.Set("hello", "world")
+		return "OK"
+	})
+
+	m.Get("/get", func(session sessions.Session) string {
+		v := session.Get("hello")
+		if v == nil {
+			return ""
+		}
+		return v.(string)
+	})
+
+  m.Run()
+}
+
+~~~
+
+## Authors
+* [Jeremy Saenz](http://github.com/codegangsta)

+ 45 - 0
vendor/github.com/martini-contrib/sessions/cookie_store.go

@@ -0,0 +1,45 @@
+package sessions
+
+import (
+	"github.com/gorilla/sessions"
+)
+
+// CookieStore is an interface that represents a Cookie based storage
+// for Sessions.
+type CookieStore interface {
+	// Store is an embedded interface so that CookieStore can be used
+	// as a session store.
+	Store
+	// Options sets the default options for each session stored in this
+	// CookieStore.
+	Options(Options)
+}
+
+// NewCookieStore returns a new CookieStore.
+//
+// Keys are defined in pairs to allow key rotation, but the common case is to set a single
+// authentication key and optionally an encryption key.
+//
+// The first key in a pair is used for authentication and the second for encryption. The
+// encryption key can be set to nil or omitted in the last pair, but the authentication key
+// is required in all pairs.
+//
+// It is recommended to use an authentication key with 32 or 64 bytes. The encryption key,
+// if set, must be either 16, 24, or 32 bytes to select AES-128, AES-192, or AES-256 modes.
+func NewCookieStore(keyPairs ...[]byte) CookieStore {
+	return &cookieStore{sessions.NewCookieStore(keyPairs...)}
+}
+
+type cookieStore struct {
+	*sessions.CookieStore
+}
+
+func (c *cookieStore) Options(options Options) {
+	c.CookieStore.Options = &sessions.Options{
+		Path:     options.Path,
+		Domain:   options.Domain,
+		MaxAge:   options.MaxAge,
+		Secure:   options.Secure,
+		HttpOnly: options.HttpOnly,
+	}
+}

+ 50 - 0
vendor/github.com/martini-contrib/sessions/redis_store.go

@@ -0,0 +1,50 @@
+package sessions
+
+import (
+	"github.com/boj/redistore"
+	"github.com/gorilla/sessions"
+)
+
+// RedisStore is an interface that represents a Cookie based storage
+// for Sessions.
+type RediStore interface {
+	// Store is an embedded interface so that RedisStore can be used
+	// as a session store.
+	Store
+	// Options sets the default options for each session stored in this
+	// CookieStore.
+	Options(Options)
+}
+
+// NewCookieStore returns a new CookieStore.
+//
+// Keys are defined in pairs to allow key rotation, but the common case is to set a single
+// authentication key and optionally an encryption key.
+//
+// The first key in a pair is used for authentication and the second for encryption. The
+// encryption key can be set to nil or omitted in the last pair, but the authentication key
+// is required in all pairs.
+//
+// It is recommended to use an authentication key with 32 or 64 bytes. The encryption key,
+// if set, must be either 16, 24, or 32 bytes to select AES-128, AES-192, or AES-256 modes.
+func NewRediStore(size int, network, address, password string, keyPairs ...[]byte) (RediStore, error) {
+	store, err := redistore.NewRediStore(size, network, address, password, keyPairs...)
+	if err != nil {
+		return nil, err
+	}
+	return &rediStore{store}, nil
+}
+
+type rediStore struct {
+	*redistore.RediStore
+}
+
+func (c *rediStore) Options(options Options) {
+	c.RediStore.Options = &sessions.Options{
+		Path:     options.Path,
+		Domain:   options.Domain,
+		MaxAge:   options.MaxAge,
+		Secure:   options.Secure,
+		HttpOnly: options.HttpOnly,
+	}
+}

+ 166 - 0
vendor/github.com/martini-contrib/sessions/sessions.go

@@ -0,0 +1,166 @@
+// Package sessions contains middleware for easy session management in Martini.
+//
+//  package main
+//
+//  import (
+//    "github.com/go-martini/martini"
+//    "github.com/martini-contrib/sessions"
+//  )
+//
+//  func main() {
+// 	  m := martini.Classic()
+//
+// 	  store := sessions.NewCookieStore([]byte("secret123"))
+// 	  m.Use(sessions.Sessions("my_session", store))
+//
+// 	  m.Get("/", func(session sessions.Session) string {
+// 		  session.Set("hello", "world")
+// 	  })
+//  }
+package sessions
+
+import (
+	"github.com/go-martini/martini"
+	"github.com/gorilla/context"
+	"github.com/gorilla/sessions"
+	"log"
+	"net/http"
+)
+
+const (
+	errorFormat = "[sessions] ERROR! %s\n"
+)
+
+// Store is an interface for custom session stores.
+type Store interface {
+	sessions.Store
+}
+
+// Options stores configuration for a session or session store.
+//
+// Fields are a subset of http.Cookie fields.
+type Options struct {
+	Path   string
+	Domain string
+	// MaxAge=0 means no 'Max-Age' attribute specified.
+	// MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0'.
+	// MaxAge>0 means Max-Age attribute present and given in seconds.
+	MaxAge   int
+	Secure   bool
+	HttpOnly bool
+}
+
+// Session stores the values and optional configuration for a session.
+type Session interface {
+	// Get returns the session value associated to the given key.
+	Get(key interface{}) interface{}
+	// Set sets the session value associated to the given key.
+	Set(key interface{}, val interface{})
+	// Delete removes the session value associated to the given key.
+	Delete(key interface{})
+	// Clear deletes all values in the session.
+	Clear()
+	// AddFlash adds a flash message to the session.
+	// A single variadic argument is accepted, and it is optional: it defines the flash key.
+	// If not defined "_flash" is used by default.
+	AddFlash(value interface{}, vars ...string)
+	// Flashes returns a slice of flash messages from the session.
+	// A single variadic argument is accepted, and it is optional: it defines the flash key.
+	// If not defined "_flash" is used by default.
+	Flashes(vars ...string) []interface{}
+	// Options sets confuguration for a session.
+	Options(Options)
+}
+
+// Sessions is a Middleware that maps a session.Session service into the Martini handler chain.
+// Sessions can use a number of storage solutions with the given store.
+func Sessions(name string, store Store) martini.Handler {
+	return func(res http.ResponseWriter, r *http.Request, c martini.Context, l *log.Logger) {
+		// Map to the Session interface
+		s := &session{name, r, l, store, nil, false}
+		c.MapTo(s, (*Session)(nil))
+
+		// Use before hook to save out the session
+		rw := res.(martini.ResponseWriter)
+		rw.Before(func(martini.ResponseWriter) {
+			if s.Written() {
+				check(s.Session().Save(r, res), l)
+			}
+		})
+
+		// clear the context, we don't need to use
+		// gorilla context and we don't want memory leaks
+		defer context.Clear(r)
+
+		c.Next()
+	}
+}
+
+type session struct {
+	name    string
+	request *http.Request
+	logger  *log.Logger
+	store   Store
+	session *sessions.Session
+	written bool
+}
+
+func (s *session) Get(key interface{}) interface{} {
+	return s.Session().Values[key]
+}
+
+func (s *session) Set(key interface{}, val interface{}) {
+	s.Session().Values[key] = val
+	s.written = true
+}
+
+func (s *session) Delete(key interface{}) {
+	delete(s.Session().Values, key)
+	s.written = true
+}
+
+func (s *session) Clear() {
+	for key := range s.Session().Values {
+		s.Delete(key)
+	}
+}
+
+func (s *session) AddFlash(value interface{}, vars ...string) {
+	s.Session().AddFlash(value, vars...)
+	s.written = true
+}
+
+func (s *session) Flashes(vars ...string) []interface{} {
+	s.written = true
+	return s.Session().Flashes(vars...)
+}
+
+func (s *session) Options(options Options) {
+	s.Session().Options = &sessions.Options{
+		Path:     options.Path,
+		Domain:   options.Domain,
+		MaxAge:   options.MaxAge,
+		Secure:   options.Secure,
+		HttpOnly: options.HttpOnly,
+	}
+}
+
+func (s *session) Session() *sessions.Session {
+	if s.session == nil {
+		var err error
+		s.session, err = s.store.Get(s.request, s.name)
+		check(err, s.logger)
+	}
+
+	return s.session
+}
+
+func (s *session) Written() bool {
+	return s.written
+}
+
+func check(err error, l *log.Logger) {
+	if err != nil {
+		l.Printf(errorFormat, err)
+	}
+}

+ 1 - 0
vendor/github.com/martini-contrib/sessions/wercker.yml

@@ -0,0 +1 @@
+box: wercker/golang@1.1.1

+ 22 - 0
vendor/github.com/xyproto/cookie/LICENSE

@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2017 Alexander F Rødseth
+
+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.
+

+ 19 - 0
vendor/github.com/xyproto/cookie/README.md

@@ -0,0 +1,19 @@
+# Cookie [![Build Status](https://travis-ci.org/xyproto/cookie.svg?branch=master)](https://travis-ci.org/xyproto/cookie) [![GoDoc](https://godoc.org/github.com/xyproto/cookie?status.svg)](http://godoc.org/github.com/xyproto/cookie) [![Report Card](https://img.shields.io/badge/go_report-A+-brightgreen.svg?style=flat)](http://goreportcard.com/report/xyproto/cookie)
+
+Functions related to cookies.
+
+Related projects
+----------------
+
+* [permissions2](https://github.com/xyproto/permissions2)
+* [permissionbolt](https://github.com/xyproto/permissionbolt)
+* [permissionhstore](https://github.com/xyproto/permissionhstore)
+* [permissionsql](https://github.com/xyproto/permissionsql)
+
+General information
+-------------------
+
+* Version: 2.0
+* License: MIT
+* Alexander F Rødseth
+

+ 21 - 0
vendor/github.com/xyproto/cookie/check.sh

@@ -0,0 +1,21 @@
+#!/bin/sh
+
+echo -n go fmt...
+go fmt && echo ok || echo fail
+
+echo -n go vet...
+go vet && echo ok || echo fail
+
+# github.com/golang/lint/golint
+echo -n golint...
+golint && echo ok || echo fail
+
+# tools from https://github.com/dominikh/go-tools
+echo -n gosimple...
+gosimple && echo ok || echo fail
+
+echo -n unused...
+gosimple && echo ok || echo fail
+
+echo -n staticcheck...
+staticcheck && echo ok || echo fail

+ 143 - 0
vendor/github.com/xyproto/cookie/cookie.go

@@ -0,0 +1,143 @@
+package cookie
+
+// Thanks to @hoisie / [web.go](https://github.com/hoisie/web) for several of these functions
+
+import (
+	"bytes"
+	"crypto/hmac"
+	"crypto/sha1"
+	"encoding/base64"
+	"fmt"
+	"io/ioutil"
+	"log"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+)
+
+const (
+	// Version number. Stable API within major version numbers.
+	Version = 2.0
+
+	// DefaultCookieTime represent how long login cookies should last, by deafault
+	DefaultCookieTime = 24 * 3600 // 24 hours
+)
+
+// SecureCookie retrieves a secure cookie from a HTTP request
+func SecureCookie(req *http.Request, name string, cookieSecret string) (string, bool) {
+	for _, cookie := range req.Cookies() {
+		if cookie.Name != name {
+			continue
+		}
+
+		parts := strings.SplitN(cookie.Value, "|", 3)
+
+		// fix potential out of range error
+		if len(parts) != 3 {
+			return "", false
+		}
+
+		val := parts[0]
+		timestamp := parts[1]
+		signature := parts[2]
+
+		if Signature(cookieSecret, []byte(val), timestamp) != signature {
+			return "", false
+		}
+
+		ts, _ := strconv.ParseInt(timestamp, 0, 64)
+		if time.Now().Unix()-31*86400 > ts {
+			return "", false
+		}
+
+		buf := bytes.NewBufferString(val)
+		encoder := base64.NewDecoder(base64.StdEncoding, buf)
+
+		res, _ := ioutil.ReadAll(encoder)
+		return string(res), true
+	}
+	return "", false
+}
+
+/*SetCookiePathWithFlags sets a cookie with an explicit path.
+ * age is the time-to-live, in seconds (0 means forever).
+ *
+ * The secure and httponly flags are documented here:
+ * https://golang.org/pkg/net/http/#Cookie
+ */
+func SetCookiePathWithFlags(w http.ResponseWriter, name, value string, age int64, path string, secure, httponly bool) {
+	var utctime time.Time
+	if age == 0 {
+		// 2^31 - 1 seconds (roughly 2038)
+		utctime = time.Unix(2147483647, 0)
+	} else {
+		utctime = time.Unix(time.Now().Unix()+age, 0)
+	}
+	cookie := http.Cookie{Name: name, Value: value, Expires: utctime, Path: path, Secure: secure, HttpOnly: httponly}
+	SetHeader(w, "Set-Cookie", cookie.String(), false)
+}
+
+// SetCookiePath sets a cookie with an explicit path.
+// age is the time-to-live, in seconds (0 means forever).
+func SetCookiePath(w http.ResponseWriter, name, value string, age int64, path string) {
+	SetCookiePathWithFlags(w, name, value, age, path, false, false)
+}
+
+// ClearCookie clears the cookie with the given cookie name and a corresponding path.
+// The cookie is cleared by setting the expiration date to 1970-01-01.
+// Note that browsers *may* be configured to not delete the cookie.
+func ClearCookie(w http.ResponseWriter, cookieName, cookiePath string) {
+	ignoredContent := "SNUSNU" // random string
+	cookie := fmt.Sprintf("%s=%s; path=%s; expires=Thu, 01 Jan 1970 00:00:00 GMT", cookieName, ignoredContent, cookiePath)
+	SetHeader(w, "Set-Cookie", cookie, true)
+}
+
+/*SetSecureCookiePathWithFlags creates and sets a secure cookie with an explicit path.
+ * age is the time-to-live, in seconds (0 means forever).
+ *
+ * The secure and httponly flags are documented here:
+ * https://golang.org/pkg/net/http/#Cookie
+ */
+func SetSecureCookiePathWithFlags(w http.ResponseWriter, name, val string, age int64, path string, cookieSecret string, secure, httponly bool) {
+	// base64 encode the value
+	if len(cookieSecret) == 0 {
+		log.Fatalln("Secret Key for secure cookies has not been set. Please use a non-empty secret.")
+	}
+	var buf bytes.Buffer
+	encoder := base64.NewEncoder(base64.StdEncoding, &buf)
+	encoder.Write([]byte(val))
+	encoder.Close()
+	vs := buf.String()
+	vb := buf.Bytes()
+	timestamp := strconv.FormatInt(time.Now().Unix(), 10)
+	sig := Signature(cookieSecret, vb, timestamp)
+	cookie := strings.Join([]string{vs, timestamp, sig}, "|")
+	SetCookiePathWithFlags(w, name, cookie, age, path, secure, httponly)
+}
+
+// SetSecureCookiePath creates and sets a secure cookie with an explicit path.
+// age is the time-to-live, in seconds (0 means forever).
+func SetSecureCookiePath(w http.ResponseWriter, name, val string, age int64, path string, cookieSecret string) {
+	SetSecureCookiePathWithFlags(w, name, val, age, path, cookieSecret, false, false)
+}
+
+// Signature retrieves the cookie signature
+func Signature(key string, val []byte, timestamp string) string {
+	hm := hmac.New(sha1.New, []byte(key))
+
+	hm.Write(val)
+	hm.Write([]byte(timestamp))
+
+	hex := fmt.Sprintf("%02x", hm.Sum(nil))
+	return hex
+}
+
+// SetHeader sets cookies in the HTTP header
+func SetHeader(w http.ResponseWriter, hdr, val string, unique bool) {
+	if unique {
+		w.Header().Set(hdr, val)
+	} else {
+		w.Header().Add(hdr, val)
+	}
+}

+ 49 - 0
vendor/github.com/xyproto/cookie/randomstring.go

@@ -0,0 +1,49 @@
+package cookie
+
+// Functions for generating random strings
+
+import (
+	"math/rand"
+)
+
+// RandomString generates a random string of a given length.
+func RandomString(length int) string {
+	b := make([]byte, length)
+	for i := 0; i < length; i++ {
+		b[i] = byte(rand.Int63() & 0xff)
+	}
+	return string(b)
+}
+
+/*RandomHumanFriendlyString generates a random, but human-friendly, string of
+ * the given length. It should be possible to read out loud and send in an email
+ * without problems. The string alternates between vowels and consontants.
+ *
+ * Example output for length 10: ykyzexebub
+ */
+func RandomHumanFriendlyString(length int) string {
+	const (
+		vowels     = "aeiouy" // email+browsers didn't like "æøå" too much
+		consonants = "bcdfghjklmnpqrstvwxz"
+	)
+	b := make([]byte, length)
+	for i := 0; i < length; i++ {
+		if i%2 == 0 {
+			b[i] = vowels[rand.Intn(len(vowels))]
+		} else {
+			b[i] = consonants[rand.Intn(len(consonants))]
+		}
+	}
+	return string(b)
+}
+
+// RandomCookieFriendlyString generates a random, but cookie-friendly, string of
+// the given length.
+func RandomCookieFriendlyString(length int) string {
+	const allowed = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
+	b := make([]byte, length)
+	for i := 0; i < length; i++ {
+		b[i] = allowed[rand.Intn(len(allowed))]
+	}
+	return string(b)
+}

+ 21 - 0
vendor/github.com/xyproto/permissionsql/LICENSE

@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2018 Alexander F. Rødseth
+
+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.

+ 335 - 0
vendor/github.com/xyproto/permissionsql/README.md

@@ -0,0 +1,335 @@
+# PermissionSQL [![Build Status](https://travis-ci.org/xyproto/permissionsql.svg?branch=master)](https://travis-ci.org/xyproto/permissionsql) [![GoDoc](https://godoc.org/github.com/xyproto/permissionsql?status.svg)](http://godoc.org/github.com/xyproto/permissionsql)
+
+Middleware for keeping track of users, login states and permissions.
+
+## Online API Documentation
+
+[godoc.org](http://godoc.org/github.com/xyproto/permissionsql)
+
+## Features and limitations
+
+* Uses secure cookies and stores user information in a MariaDB/MySQL database.
+* Suitable for running a local MariaDB/MySQL server, registering/confirming users and managing public/user/admin pages.
+* Also supports connecting to remote MariaDB/MySQL servers.
+* Supports registration and confirmation via generated confirmation codes.
+* Tries to keep things simple.
+* Only supports "public", "user" and "admin" permissions out of the box, but offers functionality for implementing more fine grained permissions, if so desired.
+* Supports [Negroni](https://github.com/codegangsta/negroni), [Martini](https://github.com/go-martini/martini), [Gin](https://github.com/gin-gonic/gin) and [Macaron](https://github.com/Unknwon/macaron).
+* Should also work with other frameworks, since the standard http.HandlerFunc is used everywhere.
+* The default permissions can be cleared with the Clear() function.
+
+## Connecting
+
+For connecting to a MariaDB/MySQL host that is running locally, the `New` function can be used. For connecting to a remote server, the `NewWithDSN` function can be used.
+
+## Requirements
+
+* MariaDB or MySQL
+* Go >= 1.7
+
+## Examples
+
+### Example for [Gin](https://github.com/gin-gonic/gin)
+
+~~~ go
+package main
+
+import (
+	"fmt"
+	"log"
+	"net/http"
+	"strings"
+
+	"github.com/gin-gonic/gin"
+	"github.com/xyproto/permissionsql"
+)
+
+func main() {
+	g := gin.New()
+
+	// New permissionsql middleware
+	perm, err := permissionsql.New()
+	if err != nil {
+		log.Fatalln(err)
+	}
+
+	// Blank slate, no default permissions
+	//perm.Clear()
+
+	// Set up a middleware handler for Gin, with a custom "permission denied" message.
+	permissionHandler := func(c *gin.Context) {
+		// Check if the user has the right admin/user rights
+		if perm.Rejected(c.Writer, c.Request) {
+			// Deny the request, don't call other middleware handlers
+			c.AbortWithStatus(http.StatusForbidden)
+			fmt.Fprint(c.Writer, "Permission denied!")
+			return
+		}
+		// Call the next middleware handler
+		c.Next()
+	}
+
+	// Logging middleware
+	g.Use(gin.Logger())
+
+	// Enable the permissionsql middleware, must come before recovery
+	g.Use(permissionHandler)
+
+	// Recovery middleware
+	g.Use(gin.Recovery())
+
+	// Get the userstate, used in the handlers below
+	userstate := perm.UserState()
+
+	g.GET("/", func(c *gin.Context) {
+		msg := ""
+		msg += fmt.Sprintf("Has user bob: %v\n", userstate.HasUser("bob"))
+		msg += fmt.Sprintf("Logged in on server: %v\n", userstate.IsLoggedIn("bob"))
+		msg += fmt.Sprintf("Is confirmed: %v\n", userstate.IsConfirmed("bob"))
+		msg += fmt.Sprintf("Username stored in cookies (or blank): %v\n", userstate.Username(c.Request))
+		msg += fmt.Sprintf("Current user is logged in, has a valid cookie and *user rights*: %v\n", userstate.UserRights(c.Request))
+		msg += fmt.Sprintf("Current user is logged in, has a valid cookie and *admin rights*: %v\n", userstate.AdminRights(c.Request))
+		msg += fmt.Sprintln("\nTry: /register, /confirm, /remove, /login, /logout, /makeadmin, /clear, /data and /admin")
+		c.String(http.StatusOK, msg)
+	})
+
+	g.GET("/register", func(c *gin.Context) {
+		userstate.AddUser("bob", "hunter1", "bob@zombo.com")
+		c.String(http.StatusOK, fmt.Sprintf("User bob was created: %v\n", userstate.HasUser("bob")))
+	})
+
+	g.GET("/confirm", func(c *gin.Context) {
+		userstate.MarkConfirmed("bob")
+		c.String(http.StatusOK, fmt.Sprintf("User bob was confirmed: %v\n", userstate.IsConfirmed("bob")))
+	})
+
+	g.GET("/remove", func(c *gin.Context) {
+		userstate.RemoveUser("bob")
+		c.String(http.StatusOK, fmt.Sprintf("User bob was removed: %v\n", !userstate.HasUser("bob")))
+	})
+
+	g.GET("/login", func(c *gin.Context) {
+		// Headers will be written, for storing a cookie
+		userstate.Login(c.Writer, "bob")
+		c.String(http.StatusOK, fmt.Sprintf("bob is now logged in: %v\n", userstate.IsLoggedIn("bob")))
+	})
+
+	g.GET("/logout", func(c *gin.Context) {
+		userstate.Logout("bob")
+		c.String(http.StatusOK, fmt.Sprintf("bob is now logged out: %v\n", !userstate.IsLoggedIn("bob")))
+	})
+
+	g.GET("/makeadmin", func(c *gin.Context) {
+		userstate.SetAdminStatus("bob")
+		c.String(http.StatusOK, fmt.Sprintf("bob is now administrator: %v\n", userstate.IsAdmin("bob")))
+	})
+
+	g.GET("/clear", func(c *gin.Context) {
+		userstate.ClearCookie(c.Writer)
+		c.String(http.StatusOK, "Clearing cookie")
+	})
+
+	g.GET("/data", func(c *gin.Context) {
+		c.String(http.StatusOK, "user page that only logged in users must see!")
+	})
+
+	g.GET("/admin", func(c *gin.Context) {
+		c.String(http.StatusOK, "super secret information that only logged in administrators must see!\n\n")
+		if usernames, err := userstate.AllUsernames(); err == nil {
+			c.String(http.StatusOK, "list of all users: "+strings.Join(usernames, ", "))
+		}
+	})
+
+	// Serve
+	g.Run(":3000")
+}
+~~~
+
+### Example for just `net/http`
+
+~~~ go
+package main
+
+import (
+	"fmt"
+	"log"
+	"net/http"
+	"strings"
+	"time"
+
+	"github.com/xyproto/permissionsql"
+	"github.com/xyproto/pinterface"
+)
+
+type permissionHandler struct {
+	// perm is a Permissions structure that can be used to deny requests
+	// and acquire the UserState. By using `pinterface.IPermissions` instead
+	// of `*permissions.Permissions`, the code is compatible with not only
+	// `permissions2`, but also other modules that uses other database
+	// backends, like `permissionbolt` which uses Bolt.
+	perm pinterface.IPermissions
+
+	// The HTTP multiplexer
+	mux *http.ServeMux
+}
+
+// Implement the ServeHTTP method to make a permissionHandler a http.Handler
+func (ph *permissionHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
+	// Check if the user has the right admin/user rights
+	if ph.perm.Rejected(w, req) {
+		// Let the user know, by calling the custom "permission denied" function
+		ph.perm.DenyFunction()(w, req)
+		// Reject the request
+		return
+	}
+	// Serve the requested page if permissions were granted
+	ph.mux.ServeHTTP(w, req)
+}
+
+func main() {
+	mux := http.NewServeMux()
+
+	// New permissions middleware
+	perm, err := permissionsql.New()
+	if err != nil {
+		log.Fatalln(err)
+	}
+
+	// Blank slate, no default permissions
+	//perm.Clear()
+
+	// Get the userstate, used in the handlers below
+	userstate := perm.UserState()
+
+	mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
+		fmt.Fprintf(w, "Has user bob: %v\n", userstate.HasUser("bob"))
+		fmt.Fprintf(w, "Logged in on server: %v\n", userstate.IsLoggedIn("bob"))
+		fmt.Fprintf(w, "Is confirmed: %v\n", userstate.IsConfirmed("bob"))
+		fmt.Fprintf(w, "Username stored in cookies (or blank): %v\n", userstate.Username(req))
+		fmt.Fprintf(w, "Current user is logged in, has a valid cookie and *user rights*: %v\n", userstate.UserRights(req))
+		fmt.Fprintf(w, "Current user is logged in, has a valid cookie and *admin rights*: %v\n", userstate.AdminRights(req))
+		fmt.Fprintf(w, "\nTry: /register, /confirm, /remove, /login, /logout, /makeadmin, /clear, /data and /admin")
+	})
+
+	mux.HandleFunc("/register", func(w http.ResponseWriter, req *http.Request) {
+		userstate.AddUser("bob", "hunter1", "bob@zombo.com")
+		fmt.Fprintf(w, "User bob was created: %v\n", userstate.HasUser("bob"))
+	})
+
+	mux.HandleFunc("/confirm", func(w http.ResponseWriter, req *http.Request) {
+		userstate.MarkConfirmed("bob")
+		fmt.Fprintf(w, "User bob was confirmed: %v\n", userstate.IsConfirmed("bob"))
+	})
+
+	mux.HandleFunc("/remove", func(w http.ResponseWriter, req *http.Request) {
+		userstate.RemoveUser("bob")
+		fmt.Fprintf(w, "User bob was removed: %v\n", !userstate.HasUser("bob"))
+	})
+
+	mux.HandleFunc("/login", func(w http.ResponseWriter, req *http.Request) {
+		userstate.Login(w, "bob")
+		fmt.Fprintf(w, "bob is now logged in: %v\n", userstate.IsLoggedIn("bob"))
+	})
+
+	mux.HandleFunc("/logout", func(w http.ResponseWriter, req *http.Request) {
+		userstate.Logout("bob")
+		fmt.Fprintf(w, "bob is now logged out: %v\n", !userstate.IsLoggedIn("bob"))
+	})
+
+	mux.HandleFunc("/makeadmin", func(w http.ResponseWriter, req *http.Request) {
+		userstate.SetAdminStatus("bob")
+		fmt.Fprintf(w, "bob is now administrator: %v\n", userstate.IsAdmin("bob"))
+	})
+
+	mux.HandleFunc("/clear", func(w http.ResponseWriter, req *http.Request) {
+		userstate.ClearCookie(w)
+		fmt.Fprintf(w, "Clearing cookie")
+	})
+
+	mux.HandleFunc("/data", func(w http.ResponseWriter, req *http.Request) {
+		fmt.Fprintf(w, "user page that only logged in users must see!")
+	})
+
+	mux.HandleFunc("/admin", func(w http.ResponseWriter, req *http.Request) {
+		fmt.Fprintf(w, "super secret information that only logged in administrators must see!\n\n")
+		if usernames, err := userstate.AllUsernames(); err == nil {
+			fmt.Fprintf(w, "list of all users: "+strings.Join(usernames, ", "))
+		}
+	})
+
+	// Custom handler for when permissions are denied
+	perm.SetDenyFunction(func(w http.ResponseWriter, req *http.Request) {
+		http.Error(w, "Permission denied!", http.StatusForbidden)
+	})
+
+	// Configure the HTTP server and permissionHandler struct
+	s := &http.Server{
+		Addr:           ":3000",
+		Handler:        &permissionHandler{perm, mux},
+		ReadTimeout:    10 * time.Second,
+		WriteTimeout:   10 * time.Second,
+		MaxHeaderBytes: 1 << 20,
+	}
+
+	log.Println("Listening for requests on port 3000")
+
+	// Start listening
+	log.Fatal(s.ListenAndServe())
+}
+~~~
+
+## Default permissions
+
+* Visiting the */admin* path prefix requires the user to be logged in with admin rights, by default.
+* These path prefixes requires the user to be logged in, by default: */repo* and */data*
+* These path prefixes are public by default: */*, */login*, */register*, */style*, */img*, */js*, */favicon.ico*, */robots.txt* and */sitemap_index.xml*
+
+The default permissions can be cleared with the `Clear()` function.
+
+## Coding style
+
+* The code shall always be formatted with `go fmt`.
+
+## Password hashing
+
+* bcrypt is used by default for hashing passwords. sha256 is also supported.
+* By default, all new password will be hashed with bcrypt.
+* For backwards compatibility, old password hashes with the length of a sha256 hash will be checked with sha256. To disable this behavior, and only ever use bcrypt, add this line: `userstate.SetPasswordAlgo("bcrypt")`
+
+## Setting and getting properties for users
+
+* Setting a property:
+
+```
+username := "bob"
+propertyName := "clever"
+propertyValue := "yes"
+
+userstate.Users().Set(username, propertyName, propertyValue)
+```
+
+* Getting a property:
+
+```
+username := "bob"
+propertyName := "clever"
+propertyValue, err := userstate.Users().Get(username, propertyName)
+if err != nil {
+	log.Print(err)
+	return err
+}
+fmt.Printf("%s is %s: %s\n", username, propertyName, propertyValue)
+```
+
+## Passing userstate between functions, files and to other Go packages
+
+Using the `*pinterface.IUserState` type (from the [pinterface](https://github.com/xyproto/pinterface) package) makes it possible to pass UserState structs between functions, also in other packages. By using this interface, it is possible to seamlessly change the database backend from, for instance, PostgreSQL ([pstore](https://github.com/xyproto/pstore)) to BoltDB ([permissionbolt](https://github.com/xyproto/permissionbolt)) or Redis ([permissions2](https://github.com/xyproto/permissions2)).
+
+[pstore](https://github.com/xyproto/pstore), [permissionsql](https://github.com/xyproto/permissionsql), [permissionbolt](https://github.com/xyproto/permissionbolt) and [permissions2](https://github.com/xyproto/permissions2) are interchangeable.
+
+
+## General information
+
+* Version: 2.1.0
+* License: MIT
+* Alexander F Rødseth &lt;xyproto@archlinux.org&gt;

+ 11 - 0
vendor/github.com/xyproto/permissionsql/TODO.md

@@ -0,0 +1,11 @@
+TODO
+====
+
+* Add ClearCookie to the examples, like for permissions2 and permissionbolt
+* Use the anti timing-attack from martini-contrib/auth/.
+* Look into supporting HTTP basic auth, but only for some paths (see xyproto/scoreserver)
+* Add custom roles for permissions3
+* Decouple the database backend for permissions3 (and add sqlite3 support)
+* Use a more international selection of letters when validating usernames (in userstate.go)
+* Let HashPassword return an error instead of panic if bcrypt should fail, for permissions3
+

+ 18 - 0
vendor/github.com/xyproto/permissionsql/go.mod

@@ -0,0 +1,18 @@
+module github.com/xyproto/permissionsql
+
+require (
+	github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7 // indirect
+	github.com/gin-gonic/gin v1.3.0
+	github.com/json-iterator/go v1.1.5 // indirect
+	github.com/mattn/go-isatty v0.0.4 // indirect
+	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
+	github.com/modern-go/reflect2 v1.0.1 // indirect
+	github.com/ugorji/go/codec v0.0.0-20181209151446-772ced7fd4c2 // indirect
+	github.com/xyproto/cookie v0.0.0-20171003173729-8ce3defb0907
+	github.com/xyproto/pinterface v0.0.0-20181004125811-9710ef24b684
+	github.com/xyproto/simplemaria v0.0.0-20181211083039-d325ae02395a
+	golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9
+	golang.org/x/sys v0.0.0-20181210030007-2a47403f2ae5 // indirect
+	gopkg.in/go-playground/validator.v8 v8.18.2 // indirect
+	gopkg.in/yaml.v2 v2.2.2 // indirect
+)

+ 38 - 0
vendor/github.com/xyproto/permissionsql/go.sum

@@ -0,0 +1,38 @@
+github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7 h1:AzN37oI0cOS+cougNAV9szl6CVoj2RYwzS3DpUQNtlY=
+github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
+github.com/gin-gonic/gin v1.3.0 h1:kCmZyPklC0gVdL728E6Aj20uYBJV93nj/TkwBTKhFbs=
+github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y=
+github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
+github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
+github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/json-iterator/go v1.1.5 h1:gL2yXlmiIo4+t+y32d4WGwOjKGYcGOuyrg46vadswDE=
+github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
+github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
+github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/ugorji/go/codec v0.0.0-20181209151446-772ced7fd4c2 h1:EICbibRW4JNKMcY+LsWmuwob+CRS1BmdRdjphAm9mH4=
+github.com/ugorji/go/codec v0.0.0-20181209151446-772ced7fd4c2/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
+github.com/xyproto/cookie v0.0.0-20171003173729-8ce3defb0907 h1:9qqWk6/29cweeD27aMqGSdk/3/Zp9/wKTQLhXfR3ix0=
+github.com/xyproto/cookie v0.0.0-20171003173729-8ce3defb0907/go.mod h1:Jkc0U5QghR0GdJHVetkXRYMciw3dGqpLR69uw8vutsY=
+github.com/xyproto/pinterface v0.0.0-20181004125811-9710ef24b684 h1:NFSurCu+HqTKLlURDwnZL2J6GQv4WKzGBuFdrO8Rimc=
+github.com/xyproto/pinterface v0.0.0-20181004125811-9710ef24b684/go.mod h1:BzQLxcJwPQpzFgOyNEL02hGO5T4VqXB1BX+lp5bE040=
+github.com/xyproto/simplemaria v0.0.0-20181211083039-d325ae02395a h1:3OOYNuuKUS6DtnAWBWoXaxGpODgpGIr5RcjCAqqI77o=
+github.com/xyproto/simplemaria v0.0.0-20181211083039-d325ae02395a/go.mod h1:nBPcys+WhnULZy2Todx8QkByMl8+252tWGQ/urdWZxk=
+golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9 h1:mKdxBk7AujPs8kU4m80U72y/zjbZ3UcXC7dClwKbUI0=
+golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181207154023-610586996380/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/sys v0.0.0-20181210030007-2a47403f2ae5 h1:SlFRMb9PEnqzqnBRCynVOhxv4vHjB2lnIoxK6p5nzFM=
+golang.org/x/sys v0.0.0-20181210030007-2a47403f2ae5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+google.golang.org/appengine v1.3.0 h1:FBSsiFRMz3LBeXIomRnVzrQwSDj4ibvcRexLG0LZGQk=
+google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ=
+gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
+gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

+ 48 - 0
vendor/github.com/xyproto/permissionsql/hashing.go

@@ -0,0 +1,48 @@
+package permissionsql
+
+import (
+	"crypto/sha256"
+	"crypto/subtle"
+
+	"golang.org/x/crypto/bcrypt"
+	"io"
+)
+
+// Hash the password with sha256 (the username is needed for salting)
+func hash_sha256(cookieSecret, username, password string) []byte {
+	hasher := sha256.New()
+	// Use the cookie secret as additional salt
+	io.WriteString(hasher, password+cookieSecret+username)
+	return hasher.Sum(nil)
+}
+
+// Hash the password with bcrypt
+func hash_bcrypt(password string) []byte {
+	hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
+	if err != nil {
+		panic("Permissions: bcrypt password hashing unsuccessful")
+	}
+	return hash
+}
+
+// Check if a given password(+username) is correct, for a given sha256 hash
+func correct_sha256(hash []byte, cookieSecret, username, password string) bool {
+	comparisonHash := hash_sha256(cookieSecret, username, password)
+	// check that the lengths are equal before calling ConstantTimeCompare
+	if len(hash) != len(comparisonHash) {
+		return false
+	}
+	// prevents timing attack
+	return subtle.ConstantTimeCompare(hash, comparisonHash) == 1
+}
+
+// Check if a given password is correct, for a given bcrypt hash
+func correct_bcrypt(hash []byte, password string) bool {
+	// prevents timing attack
+	return bcrypt.CompareHashAndPassword(hash, []byte(password)) == nil
+}
+
+// Check if the given hash is sha256 (when the alternative is only bcrypt)
+func is_sha256(hash []byte) bool {
+	return len(hash) == 32
+}

+ 183 - 0
vendor/github.com/xyproto/permissionsql/permissionsql.go

@@ -0,0 +1,183 @@
+// Package permissionsql provides a way to keeping track of users, login states and permissions.
+package permissionsql
+
+import (
+	"github.com/xyproto/pinterface"
+	"net/http"
+	"strings"
+)
+
+// The structure that keeps track of the permissions for various path prefixes
+type Permissions struct {
+	state              *UserState
+	adminPathPrefixes  []string
+	userPathPrefixes   []string
+	publicPathPrefixes []string
+	rootIsPublic       bool
+	denied             http.HandlerFunc
+}
+
+const (
+	// Version number. Stable API within major version numbers.
+	Version = 2.1
+)
+
+// Initialize a Permissions struct with all the default settings.
+// This will also connect to the database host at port 3306.
+func New() (*Permissions, error) {
+	state, err := NewUserStateSimple()
+	if err != nil {
+		return nil, err
+	}
+	return NewPermissions(state), nil
+}
+
+// Initialize a Permissions struct with a database connection string
+func NewWithConf(connectionString string) (*Permissions, error) {
+	state, err := NewUserState(connectionString, true)
+	if err != nil {
+		return nil, err
+	}
+	return NewPermissions(state), nil
+}
+
+// Initialize a Permissions struct with a dsn
+func NewWithDSN(connectionString string, database_name string) (*Permissions, error) {
+	state, err := NewUserStateWithDSN(connectionString, database_name, true)
+	if err != nil {
+		return nil, err
+	}
+	return NewPermissions(state), nil
+}
+
+// Initialize a Permissions struct with the given UserState and
+// a few default paths for admin/user/public path prefixes.
+func NewPermissions(state *UserState) *Permissions {
+	// default permissions
+	return &Permissions{state,
+		[]string{"/admin"},         // admin path prefixes
+		[]string{"/repo", "/data"}, // user path prefixes
+		[]string{"/", "/login", "/register", "/favicon.ico", "/style", "/img", "/js",
+			"/favicon.ico", "/robots.txt", "/sitemap_index.xml"}, // public
+		true,
+		PermissionDenied}
+}
+
+// Specify the http.HandlerFunc for when the permissions are denied
+func (perm *Permissions) SetDenyFunction(f http.HandlerFunc) {
+	perm.denied = f
+}
+
+// Get the current http.HandlerFunc for when permissions are denied
+func (perm *Permissions) DenyFunction() http.HandlerFunc {
+	return perm.denied
+}
+
+// Retrieve the UserState struct
+func (perm *Permissions) UserState() pinterface.IUserState {
+	return perm.state
+}
+
+// Set everything to public
+func (perm *Permissions) Clear() {
+	perm.adminPathPrefixes = []string{}
+	perm.userPathPrefixes = []string{}
+}
+
+// Add an url path prefix that is a page for the logged in administrators
+func (perm *Permissions) AddAdminPath(prefix string) {
+	perm.adminPathPrefixes = append(perm.adminPathPrefixes, prefix)
+}
+
+// Add an url path prefix that is a page for the logged in users
+func (perm *Permissions) AddUserPath(prefix string) {
+	perm.userPathPrefixes = append(perm.userPathPrefixes, prefix)
+}
+
+// Add an url path prefix that is a public page
+func (perm *Permissions) AddPublicPath(prefix string) {
+	perm.publicPathPrefixes = append(perm.publicPathPrefixes, prefix)
+}
+
+// Set all url path prefixes that are for the logged in administrator pages
+func (perm *Permissions) SetAdminPath(pathPrefixes []string) {
+	perm.adminPathPrefixes = pathPrefixes
+}
+
+// Set all url path prefixes that are for the logged in user pages
+func (perm *Permissions) SetUserPath(pathPrefixes []string) {
+	perm.userPathPrefixes = pathPrefixes
+}
+
+// Set all url path prefixes that are for the public pages
+func (perm *Permissions) SetPublicPath(pathPrefixes []string) {
+	perm.publicPathPrefixes = pathPrefixes
+}
+
+// The default "permission denied" http handler.
+func PermissionDenied(w http.ResponseWriter, req *http.Request) {
+	http.Error(w, "Permission denied.", http.StatusForbidden)
+}
+
+// Check if a given request should be rejected.
+func (perm *Permissions) Rejected(w http.ResponseWriter, req *http.Request) bool {
+	reject := false
+	path := req.URL.Path // the path of the url that the user wish to visit
+
+	// If it's not "/" and set to be public regardless of permissions
+	if !(perm.rootIsPublic && path == "/") {
+
+		// Reject if it is an admin page and user does not have admin permissions
+		for _, prefix := range perm.adminPathPrefixes {
+			if strings.HasPrefix(path, prefix) {
+				if !perm.state.AdminRights(req) {
+					reject = true
+					break
+				}
+			}
+		}
+
+		if !reject {
+			// Reject if it's a user page and the user does not have user rights
+			for _, prefix := range perm.userPathPrefixes {
+				if strings.HasPrefix(path, prefix) {
+					if !perm.state.UserRights(req) {
+						reject = true
+						break
+					}
+				}
+			}
+		}
+
+		if !reject {
+			// Reject if it's not a public page
+			found := false
+			for _, prefix := range perm.publicPathPrefixes {
+				if strings.HasPrefix(path, prefix) {
+					found = true
+					break
+				}
+			}
+			if !found {
+				reject = true
+			}
+		}
+
+	}
+
+	return reject
+}
+
+// Middleware handler (compatible with Negroni)
+func (perm *Permissions) ServeHTTP(w http.ResponseWriter, req *http.Request, next http.HandlerFunc) {
+	// Check if the user has the right admin/user rights
+	if perm.Rejected(w, req) {
+		// Get and call the Permission Denied function
+		perm.DenyFunction()(w, req)
+		// Reject the request by not calling the next handler below
+		return
+	}
+
+	// Call the next middleware handler
+	next(w, req)
+}

+ 619 - 0
vendor/github.com/xyproto/permissionsql/userstate.go

@@ -0,0 +1,619 @@
+package permissionsql
+
+import (
+	"errors"
+	"fmt"
+	"math/rand"
+	"net/http"
+	"time"
+
+	"github.com/xyproto/cookie"         // For cookies
+	"github.com/xyproto/pinterface"     // For interfaces
+	db "github.com/xyproto/simplemaria" // MariaDB/MySQL database wrapper
+)
+
+const (
+	// username:password@host:port/database
+	defaultConnectionString = "localhost:3306/"
+)
+
+var (
+	minConfirmationCodeLength = 20 // minimum length of the confirmation code
+
+	ErrCookieGetUsername        = errors.New("Could not retrieve the username from browser cookie")
+	ErrCookieEmptyUsername      = errors.New("Can't set cookie for empty username")
+	ErrCookieUserMissing        = errors.New("Can't store cookie for non-existsing user")
+	ErrOutOfConfirmationCodes   = errors.New("Too many generated confirmation codes are not unique")
+	ErrAllUsersConfirmedAlready = errors.New("All existing users are already confirmed")
+	ErrConfirmationCodeExpired  = errors.New("The confirmation code is no longer valid")
+	ErrMissingUserAtConfirm     = errors.New("The user that is to be confirmed no longer exists")
+	ErrInvalidCharacters        = errors.New("Only letters, numbers and underscore are allowed in usernames")
+	ErrUsernameAsPassword       = errors.New("Username and password must be different, try another password")
+)
+
+type UserState struct {
+	users             *db.HashMap // Hash map of users, with several different fields per user ("loggedin", "confirmed", "email" etc)
+	usernames         *db.Set     // A list of all usernames, for easy enumeration
+	unconfirmed       *db.Set     // A list of unconfirmed usernames, for easy enumeration
+	host              *db.Host    // A database host
+	cookieSecret      string      // Secret for storing secure cookies
+	cookieTime        int64       // How long a cookie should last, in seconds
+	passwordAlgorithm string      // The hashing algorithm to utilize default: "bcrypt+" allowed: ("sha256", "bcrypt", "bcrypt+")
+}
+
+// Create a new *UserState that can be used for managing users.
+// The random number generator will be seeded after generating the cookie secret.
+// A Host* for the local MariaDB/MySQL server will be created.
+func NewUserStateSimple() (*UserState, error) {
+	// connection string | initialize random generator after generating the cookie secret
+	return NewUserState(defaultConnectionString, true)
+}
+
+// Create a new *UserState that can be used for managing users.
+// connectionString may be on the form "username:password@host:port/database".
+// If randomseed is true, the random number generator will be seeded after generating the cookie secret (true is a good default value).
+func NewUserStateWithDSN(connectionString string, database_name string, randomseed bool) (*UserState, error) {
+	// Test connection
+	if err := db.TestConnectionHostWithDSN(connectionString); err != nil {
+		return nil, err
+	}
+
+	host := db.NewHostWithDSN(connectionString, database_name)
+
+	state := new(UserState)
+
+	var err error
+	state.users, err = db.NewHashMap(host, "users")
+	if err != nil {
+		return nil, err
+	}
+	state.usernames, err = db.NewSet(host, "usernames")
+	if err != nil {
+		return nil, err
+	}
+	state.unconfirmed, err = db.NewSet(host, "unconfirmed")
+	if err != nil {
+		return nil, err
+	}
+
+	state.host = host
+
+	// For the secure cookies
+	// This must happen before the random seeding, or
+	// else people will have to log in again after every server restart
+	state.cookieSecret = cookie.RandomCookieFriendlyString(30)
+
+	// Seed the random number generator
+	if randomseed {
+		rand.Seed(time.Now().UnixNano())
+	}
+
+	// Cookies lasts for 24 hours by default. Specified in seconds.
+	state.cookieTime = 3600 * 24
+
+	// Default password hashing algorithm is "bcrypt+", which is the same as
+	// "bcrypt", but with backwards compatibility for checking sha256 hashes.
+	state.passwordAlgorithm = "bcrypt+" // "bcrypt+", "bcrypt" or "sha256"
+
+	if err := host.Ping(); err != nil {
+		defer host.Close()
+		return nil, fmt.Errorf("Error when pinging %s: %s", connectionString, err)
+	}
+
+	return state, nil
+}
+
+// Create a new *UserState that can be used for managing users.
+// connectionString may be on the form "username:password@host:port/database".
+// If randomseed is true, the random number generator will be seeded after generating the cookie secret (true is a good default value).
+func NewUserState(connectionString string, randomseed bool) (*UserState, error) {
+	// Test connection
+	if err := db.TestConnectionHost(connectionString); err != nil {
+		return nil, err
+	}
+
+	host := db.NewHost(connectionString)
+
+	state := new(UserState)
+
+	var err error
+	state.users, err = db.NewHashMap(host, "users")
+	if err != nil {
+		return nil, err
+	}
+	state.usernames, err = db.NewSet(host, "usernames")
+	if err != nil {
+		return nil, err
+	}
+	state.unconfirmed, err = db.NewSet(host, "unconfirmed")
+	if err != nil {
+		return nil, err
+	}
+
+	state.host = host
+
+	// For the secure cookies
+	// This must happen before the random seeding, or
+	// else people will have to log in again after every server restart
+	state.cookieSecret = cookie.RandomCookieFriendlyString(30)
+
+	// Seed the random number generator
+	if randomseed {
+		rand.Seed(time.Now().UnixNano())
+	}
+
+	// Cookies lasts for 24 hours by default. Specified in seconds.
+	state.cookieTime = 3600 * 24
+
+	// Default password hashing algorithm is "bcrypt+", which is the same as
+	// "bcrypt", but with backwards compatibility for checking sha256 hashes.
+	state.passwordAlgorithm = "bcrypt+" // "bcrypt+", "bcrypt" or "sha256"
+
+	if err := host.Ping(); err != nil {
+		defer host.Close()
+		return nil, fmt.Errorf("Error when pinging %s: %s", connectionString, err)
+	}
+
+	return state, nil
+}
+
+// Get the database host
+func (state *UserState) Host() pinterface.IHost {
+	return state.host
+}
+
+// Close the connection to the database host
+func (state *UserState) Close() {
+	state.host.Close()
+}
+
+// Check if the current user is logged in and has user rights.
+func (state *UserState) UserRights(req *http.Request) bool {
+	username, err := state.UsernameCookie(req)
+	if err != nil {
+		return false
+	}
+	return state.IsLoggedIn(username)
+}
+
+// Check if the given username exists.
+func (state *UserState) HasUser(username string) bool {
+	val, err := state.usernames.Has(username)
+	if err != nil {
+		// This happened at concurrent connections before introducing the connection pool
+		panic("ERROR: Lost connection to database?")
+	}
+	return val
+}
+
+// Return the boolean value for a given username and fieldname.
+// If the user or field is missing, false will be returned.
+// Useful for states where it makes sense that the returned value is not true
+// unless everything is in order.
+func (state *UserState) BooleanField(username, fieldname string) bool {
+	hasUser := state.HasUser(username)
+	if !hasUser {
+		return false
+	}
+	value, err := state.users.Get(username, fieldname)
+	if err != nil {
+		return false
+	}
+	return value == "true"
+}
+
+// Store a boolean value for the given username and custom fieldname.
+func (state *UserState) SetBooleanField(username, fieldname string, val bool) {
+	strval := "false"
+	if val {
+		strval = "true"
+	}
+	state.users.Set(username, fieldname, strval)
+}
+
+// Check if the given username is confirmed.
+func (state *UserState) IsConfirmed(username string) bool {
+	return state.BooleanField(username, "confirmed")
+}
+
+// Checks if the given username is logged in.
+func (state *UserState) IsLoggedIn(username string) bool {
+	if !state.HasUser(username) {
+		return false
+	}
+	status, err := state.users.Get(username, "loggedin")
+	if err != nil {
+		// Returns "no" if the status can not be retrieved
+		return false
+	}
+	return status == "true"
+}
+
+// Check if the current user is logged in and has administrator rights.
+func (state *UserState) AdminRights(req *http.Request) bool {
+	username, err := state.UsernameCookie(req)
+	if err != nil {
+		return false
+	}
+	return state.IsLoggedIn(username) && state.IsAdmin(username)
+}
+
+// Check if the given username is an administrator.
+func (state *UserState) IsAdmin(username string) bool {
+	if !state.HasUser(username) {
+		return false
+	}
+	status, err := state.users.Get(username, "admin")
+	if err != nil {
+		return false
+	}
+	return status == "true"
+}
+
+// Retrieve the username that is stored in a cookie in the browser, if available.
+func (state *UserState) UsernameCookie(req *http.Request) (string, error) {
+	username, ok := cookie.SecureCookie(req, "user", state.cookieSecret)
+	if ok && (username != "") {
+		return username, nil
+	}
+	return "", ErrCookieGetUsername
+
+}
+
+// Store the given username in a cookie in the browser, if possible.
+// The user must exist.
+func (state *UserState) SetUsernameCookie(w http.ResponseWriter, username string) error {
+	if username == "" {
+		return ErrCookieEmptyUsername
+	}
+	if !state.HasUser(username) {
+		return ErrCookieUserMissing
+	}
+	// Create a cookie that lasts for a while ("timeout" seconds),
+	// this is the equivivalent of a session for a given username.
+	cookie.SetSecureCookiePath(w, "user", username, state.cookieTime, "/", state.cookieSecret)
+	return nil
+}
+
+// Get a list of all usernames.
+func (state *UserState) AllUsernames() ([]string, error) {
+	return state.usernames.GetAll()
+}
+
+// Get the email for the given username.
+func (state *UserState) Email(username string) (string, error) {
+	return state.users.Get(username, "email")
+}
+
+// Get the password hash for the given username.
+func (state *UserState) PasswordHash(username string) (string, error) {
+	return state.users.Get(username, "password")
+}
+
+// Get all registered users that are not yet confirmed.
+func (state *UserState) AllUnconfirmedUsernames() ([]string, error) {
+	return state.unconfirmed.GetAll()
+}
+
+// Get the confirmation code for a specific user.
+func (state *UserState) ConfirmationCode(username string) (string, error) {
+	return state.users.Get(username, "confirmationCode")
+}
+
+// Get the users HashMap.
+func (state *UserState) Users() pinterface.IHashMap {
+	return state.users
+}
+
+// Add a user that is registered but not confirmed.
+func (state *UserState) AddUnconfirmed(username, confirmationCode string) {
+	state.unconfirmed.Add(username)
+	state.users.Set(username, "confirmationCode", confirmationCode)
+}
+
+// Remove a user that is registered but not confirmed.
+func (state *UserState) RemoveUnconfirmed(username string) {
+	state.unconfirmed.Del(username)
+	state.users.DelKey(username, "confirmationCode")
+}
+
+// Mark a user as confirmed.
+func (state *UserState) MarkConfirmed(username string) {
+	state.users.Set(username, "confirmed", "true")
+}
+
+// Remove user and login status.
+func (state *UserState) RemoveUser(username string) {
+	state.usernames.Del(username)
+	// Remove additional data as well
+	//state.users.DelKey(username, "loggedin")
+	state.users.Del(username)
+}
+
+// Mark user as an administrator.
+func (state *UserState) SetAdminStatus(username string) {
+	state.users.Set(username, "admin", "true")
+}
+
+// Mark user as a regular user.
+func (state *UserState) RemoveAdminStatus(username string) {
+	state.users.Set(username, "admin", "false")
+}
+
+// Creates a user from the username and password hash, does not check for rights.
+func (state *UserState) addUserUnchecked(username, passwordHash, email string) {
+	// Add the user
+	state.usernames.Add(username)
+
+	// Add password and email
+	state.users.Set(username, "password", passwordHash)
+	state.users.Set(username, "email", email)
+
+	// Addditional fields
+	additionalfields := []string{"loggedin", "confirmed", "admin"}
+	for _, fieldname := range additionalfields {
+		state.users.Set(username, fieldname, "false")
+	}
+}
+
+// Creates a user and hashes the password, does not check for rights.
+// The given data must be valid.
+func (state *UserState) AddUser(username, password, email string) {
+	passwordHash := state.HashPassword(username, password)
+	state.addUserUnchecked(username, passwordHash, email)
+}
+
+// Mark the user as logged in. Use the Login function instead, unless cookies are not involved.
+func (state *UserState) SetLoggedIn(username string) {
+	state.users.Set(username, "loggedin", "true")
+}
+
+// Mark the user as logged out.
+func (state *UserState) SetLoggedOut(username string) {
+	state.users.Set(username, "loggedin", "false")
+}
+
+// Convenience function for logging a user in and storing the username in a cookie.
+// Returns an error if the cookie could not be set.
+func (state *UserState) Login(w http.ResponseWriter, username string) error {
+	state.SetLoggedIn(username)
+	return state.SetUsernameCookie(w, username)
+}
+
+// Try to clear the user cookie by setting it to expired.
+// Some browsers *may* be configured to keep cookies even after this.
+func (state *UserState) ClearCookie(w http.ResponseWriter) {
+	cookie.ClearCookie(w, "user", "/")
+}
+
+// Convenience function for logging a user out.
+func (state *UserState) Logout(username string) {
+	state.SetLoggedOut(username)
+}
+
+// Convenience function that will return a username (from the browser cookie) or an empty string.
+func (state *UserState) Username(req *http.Request) string {
+	username, err := state.UsernameCookie(req)
+	if err != nil {
+		return ""
+	}
+	return username
+}
+
+// Get how long a login cookie should last, in seconds.
+func (state *UserState) CookieTimeout(username string) int64 {
+	return state.cookieTime
+}
+
+// Set how long a login cookie should last, in seconds.
+func (state *UserState) SetCookieTimeout(cookieTime int64) {
+	state.cookieTime = cookieTime
+}
+
+// CookieSecret returns the current cookie secret
+func (state *UserState) CookieSecret() string {
+	return state.cookieSecret
+}
+
+// SetCookieSecret sets the current cookie secret
+func (state *UserState) SetCookieSecret(cookieSecret string) {
+	state.cookieSecret = cookieSecret
+}
+
+// PasswordAlgo returns the current password hashing algorithm.
+func (state *UserState) PasswordAlgo() string {
+	return state.passwordAlgorithm
+}
+
+// Set the password hashing algorithm that should be used.
+// The default is "bcrypt+".
+// Possible values are:
+//    bcrypt  -> Store and check passwords with the bcrypt hash.
+//    sha256  -> Store and check passwords with the sha256 hash.
+//    bcrypt+ -> Store passwords with bcrypt, but check with both
+//               bcrypt and sha256, for backwards compatibility
+//               with old passwords that has been stored as sha256.
+func (state *UserState) SetPasswordAlgo(algorithm string) error {
+	switch algorithm {
+	case "sha256", "bcrypt", "bcrypt+":
+		state.passwordAlgorithm = algorithm
+	default:
+		return errors.New("Permissions: " + algorithm + " is an unsupported encryption algorithm")
+	}
+	return nil
+}
+
+// Hash the password (takes a username as well, it can be used for salting).
+func (state *UserState) HashPassword(username, password string) string {
+	switch state.passwordAlgorithm {
+	case "sha256":
+		return string(hash_sha256(state.cookieSecret, username, password))
+	case "bcrypt", "bcrypt+":
+		return string(hash_bcrypt(password))
+	}
+	// Only valid password algorithms should be allowed to set
+	return ""
+}
+
+// SetPassword sets/changes the password for a user.
+// Does not take a password hash, will hash the password string.
+func (state *UserState) SetPassword(username, password string) {
+	state.users.Set(username, "password", state.HashPassword(username, password))
+}
+
+// Return the stored hash, or an empty byte slice.
+func (state *UserState) stored_hash(username string) []byte {
+	hashString, err := state.PasswordHash(username)
+	if err != nil {
+		return []byte{}
+	}
+	return []byte(hashString)
+}
+
+// Check if a password is correct. username is needed because it is part of the hash.
+func (state *UserState) CorrectPassword(username, password string) bool {
+
+	if !state.HasUser(username) {
+		return false
+	}
+
+	// Retrieve the stored password hash
+	hash := state.stored_hash(username)
+	if len(hash) == 0 {
+		return false
+	}
+
+	// Check the password with the right password algorithm
+	switch state.passwordAlgorithm {
+	case "sha256":
+		return correct_sha256(hash, state.cookieSecret, username, password)
+	case "bcrypt":
+		return correct_bcrypt(hash, password)
+	case "bcrypt+": // for backwards compatibility with sha256
+		if is_sha256(hash) && correct_sha256(hash, state.cookieSecret, username, password) {
+			return true
+		}
+		return correct_bcrypt(hash, password)
+	}
+	return false
+}
+
+// Goes through all the confirmationCodes of all the unconfirmed users
+// and checks if this confirmationCode already is in use.
+func (state *UserState) AlreadyHasConfirmationCode(confirmationCode string) bool {
+	unconfirmedUsernames, err := state.AllUnconfirmedUsernames()
+	if err != nil {
+		return false
+	}
+	for _, aUsername := range unconfirmedUsernames {
+		aConfirmationCode, err := state.ConfirmationCode(aUsername)
+		if err != nil {
+			// If the confirmation code can not be found, that's okay too
+			return false
+		}
+		if confirmationCode == aConfirmationCode {
+			// Found it
+			return true
+		}
+	}
+	return false
+}
+
+// Given a unique confirmation code, find the corresponding username.
+func (state *UserState) FindUserByConfirmationCode(confirmationcode string) (string, error) {
+	unconfirmedUsernames, err := state.AllUnconfirmedUsernames()
+	if err != nil {
+		return "", ErrAllUsersConfirmedAlready
+	}
+
+	// Find the username by looking up the confirmationcode on unconfirmed users
+	username := ""
+	for _, aUsername := range unconfirmedUsernames {
+		aConfirmationCode, err := state.ConfirmationCode(aUsername)
+		if err != nil {
+			// If the confirmation code can not be found, just skip this one
+			continue
+		}
+		if confirmationcode == aConfirmationCode {
+			// Found the right user
+			username = aUsername
+			break
+		}
+	}
+
+	// Check that the user is there
+	if username == "" {
+		return username, ErrConfirmationCodeExpired
+	}
+	if !state.HasUser(username) {
+		return username, ErrMissingUserAtConfirm
+	}
+
+	return username, nil
+}
+
+// Remove the username from the list of unconfirmed users and mark the user as confirmed.
+func (state *UserState) Confirm(username string) {
+	// Remove from the list of unconfirmed usernames
+	state.RemoveUnconfirmed(username)
+
+	// Mark user as confirmed
+	state.MarkConfirmed(username)
+}
+
+// Take a confirmation code and mark the corresponding unconfirmed user as confirmed.
+func (state *UserState) ConfirmUserByConfirmationCode(confirmationcode string) error {
+	username, err := state.FindUserByConfirmationCode(confirmationcode)
+	if err != nil {
+		return err
+	}
+	state.Confirm(username)
+	return nil
+}
+
+// Set the minimum length of the user confirmation code. The default is 20.
+func (state *UserState) SetMinimumConfirmationCodeLength(length int) {
+	minConfirmationCodeLength = length
+}
+
+// Generate a unique confirmation code that can be used for confirming users.
+func (state *UserState) GenerateUniqueConfirmationCode() (string, error) {
+	const maxConfirmationCodeLength = 100 // when are the generated confirmation codes unreasonably long
+	length := minConfirmationCodeLength
+	confirmationCode := cookie.RandomHumanFriendlyString(length)
+	for state.AlreadyHasConfirmationCode(confirmationCode) {
+		// Increase the length of the confirmationCode random string every time there is a collision
+		length++
+		confirmationCode = cookie.RandomHumanFriendlyString(length)
+		if length > maxConfirmationCodeLength {
+			// This should never happen
+			return confirmationCode, ErrOutOfConfirmationCodes
+		}
+	}
+	return confirmationCode, nil
+}
+
+// Check that the given username and password are different.
+// Also check if the chosen username only contains letters, numbers and/or underscore.
+// Use the "CorrectPassword" function for checking if the password is correct.
+func ValidUsernamePassword(username, password string) error {
+	const allowed_letters = "abcdefghijklmnopqrstuvwxyzæøåABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ_0123456789"
+NEXT:
+	for _, letter := range username {
+		for _, allowedLetter := range allowed_letters {
+			if letter == allowedLetter {
+				continue NEXT // check the next letter in the username
+			}
+		}
+		return ErrInvalidCharacters
+	}
+	if username == password {
+		return ErrUsernameAsPassword
+	}
+	return nil
+}
+
+// Return a struct for creating datastructures
+func (state *UserState) Creator() pinterface.ICreator {
+	return db.NewCreator(state.host)
+}

+ 22 - 0
vendor/github.com/xyproto/pinterface/LICENSE

@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2018 Alexander F. Rødseth
+
+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.
+

+ 16 - 0
vendor/github.com/xyproto/pinterface/README.md

@@ -0,0 +1,16 @@
+# pinterface
+
+Interfaces for:
+---------------
+
+* Redis: [permissions2](https://github.com/xyproto/permissions2) and [simpleredis](https://github.com/xyproto/simpleredis)
+* Bolt: [permissionbolt](https://github.com/xyproto/permissionbolt) and [simplebolt](https://github.com/xyproto/simplebolt)
+* MariaDB/MySQL: [permissionsql](https://github.com/xyproto/permissionsql) and [simplemaria](https://github.com/xyproto/simplemaria)
+* PostgreSQL: [pstore](https://github.com/xyproto/pstore) and [simplehstore](https://github.com/xyproto/simplehstore)
+
+General information
+-------------------
+
+* Version 5.0.0
+* License: MIT
+* Author: Alexander F Rødseth &lt;xyproto@archlinux.org&gt;

+ 1 - 0
vendor/github.com/xyproto/pinterface/go.mod

@@ -0,0 +1 @@
+module github.com/xyproto/pinterface

+ 142 - 0
vendor/github.com/xyproto/pinterface/pinterface.go

@@ -0,0 +1,142 @@
+// Package pinterface provides interface types for the xyproto/simple* and xyproto/permission* packages
+package pinterface
+
+import "net/http"
+
+// Stable API within the same version number
+const Version = 5.0
+
+// Database interfaces
+
+type IList interface {
+	Add(value string) error
+	All() ([]string, error)        // GetAll in version 4.0
+	Last() (string, error)         // GetLast in version 4.0
+	LastN(n int) ([]string, error) // GetLastN in version 4.0
+	Remove() error
+	Clear() error
+}
+
+type ISet interface {
+	Add(value string) error
+	Has(value string) (bool, error)
+	All() ([]string, error) // GetAll in version 4.0
+	Del(value string) error
+	Remove() error
+	Clear() error
+}
+
+type IHashMap interface {
+	Set(owner, key, value string) error
+	Get(owner, key string) (string, error)
+	Has(owner, key string) (bool, error)
+	Exists(owner string) (bool, error)
+	All() ([]string, error) // GetAll in version 4.0
+	Keys(owner string) ([]string, error)
+	DelKey(owner, key string) error
+	Del(key string) error
+	Remove() error
+	Clear() error
+}
+
+type IKeyValue interface {
+	Set(key, value string) error
+	Get(key string) (string, error)
+	Del(key string) error
+	Inc(key string) (string, error)
+	Remove() error
+	Clear() error
+}
+
+// Interface for making it possible to depend on different versions of the permission package,
+// or other packages that implement userstates.
+type IUserState interface {
+	UserRights(req *http.Request) bool
+	HasUser(username string) bool
+	BooleanField(username, fieldname string) bool
+	SetBooleanField(username, fieldname string, val bool)
+	IsConfirmed(username string) bool
+	IsLoggedIn(username string) bool
+	AdminRights(req *http.Request) bool
+	IsAdmin(username string) bool
+	UsernameCookie(req *http.Request) (string, error)
+	SetUsernameCookie(w http.ResponseWriter, username string) error
+	AllUsernames() ([]string, error)
+	Email(username string) (string, error)
+	PasswordHash(username string) (string, error)
+	AllUnconfirmedUsernames() ([]string, error)
+	ConfirmationCode(username string) (string, error)
+	AddUnconfirmed(username, confirmationCode string)
+	RemoveUnconfirmed(username string)
+	MarkConfirmed(username string)
+	RemoveUser(username string)
+	SetAdminStatus(username string)
+	RemoveAdminStatus(username string)
+	AddUser(username, password, email string)
+	SetLoggedIn(username string)
+	SetLoggedOut(username string)
+	Login(w http.ResponseWriter, username string) error
+	ClearCookie(w http.ResponseWriter)
+	Logout(username string)
+	Username(req *http.Request) string
+	CookieTimeout(username string) int64
+	SetCookieTimeout(cookieTime int64)
+	CookieSecret() string
+	SetCookieSecret(cookieSecret string)
+	PasswordAlgo() string
+	SetPasswordAlgo(algorithm string) error
+	HashPassword(username, password string) string
+	SetPassword(username, password string)
+	CorrectPassword(username, password string) bool
+	AlreadyHasConfirmationCode(confirmationCode string) bool
+	FindUserByConfirmationCode(confirmationcode string) (string, error)
+	Confirm(username string)
+	ConfirmUserByConfirmationCode(confirmationcode string) error
+	SetMinimumConfirmationCodeLength(length int)
+	GenerateUniqueConfirmationCode() (string, error)
+
+	Users() IHashMap
+	Host() IHost
+	Creator() ICreator
+}
+
+// Data structure creator
+type ICreator interface {
+	NewList(id string) (IList, error)
+	NewSet(id string) (ISet, error)
+	NewHashMap(id string) (IHashMap, error)
+	NewKeyValue(id string) (IKeyValue, error)
+}
+
+// Database host (or file)
+type IHost interface {
+	Ping() error
+	Close()
+}
+
+// Redis host (implemented structures can also be an IHost, of course)
+type IRedisHost interface {
+	Pool()
+	DatabaseIndex()
+}
+
+// Redis data structure creator
+type IRedisCreator interface {
+	SelectDatabase(dbindex int)
+}
+
+// Middleware for permissions
+type IPermissions interface {
+	SetDenyFunction(f http.HandlerFunc)
+	DenyFunction() http.HandlerFunc
+	UserState() IUserState
+	Clear()
+	AddAdminPath(prefix string)
+	AddUserPath(prefix string)
+	AddPublicPath(prefix string)
+	SetAdminPath(pathPrefixes []string)
+	SetUserPath(pathPrefixes []string)
+	SetPublicPath(pathPrefixes []string)
+	Rejected(w http.ResponseWriter, req *http.Request) bool
+	ServeHTTP(w http.ResponseWriter, req *http.Request, next http.HandlerFunc)
+}

+ 21 - 0
vendor/github.com/xyproto/simplemaria/LICENSE

@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2018 Alexander F. Rødseth
+
+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.

+ 91 - 0
vendor/github.com/xyproto/simplemaria/README.md

@@ -0,0 +1,91 @@
+SimpleMaria
+===========
+
+[![Build Status](https://travis-ci.org/xyproto/simplemaria.svg?branch=master)](https://travis-ci.org/xyproto/simplemaria) [![GoDoc](https://godoc.org/github.com/xyproto/simplemaria?status.svg)](http://godoc.org/github.com/xyproto/simplemaria)
+
+An easy way to use a MariaDB/MySQL database from Go.
+
+Online API Documentation
+------------------------
+
+[godoc.org](http://godoc.org/github.com/xyproto/simplemaria)
+
+
+Features and limitations
+------------------------
+
+* Supports simple use of lists, hashmaps, sets and key/values.
+* Deals mainly with strings.
+* Uses the [mysql](https://github.com/go-sql-driver/mysql) package.
+* Modeled after [simpleredis](https://github.com/xyproto/simpleredis).
+* The hash maps behaves like hash maps, but are not backed by actual hashmaps, unlike with [simpleredis](https://github.com/xyproto/simpleredis). This is for keeping compatibility with simpleredis. If performance when scaling up is a concern, simpleredis backed by [redis](https://redis.io) might be a better choice.
+* MariaDB/MySQL normally has issues with variable size UTF-8 strings, even for for some combinations of characters. This package avoids these problems by compressing and hex encoding the data before storing in the database. This may slow down or speed up the time it takes to access the data, depending on your setup, but it's a safe way to encode *any* string. This behavior is optional and can be disabled with `host.SetRawUTF8(true)`, (to just use `utf8mb4`).
+
+
+Sample usage
+------------
+
+~~~go
+package main
+
+import (
+	"log"
+
+	"github.com/xyproto/simplemaria"
+)
+
+func main() {
+	// Check if the simplemaria service is up
+	if err := db.TestConnection(); err != nil {
+		log.Fatalln("Could not connect to local database. Is the service up and running?")
+	}
+
+	// Create a Host, connect to the local db server
+	host := db.New()
+
+	// Connecting to a different host/port
+	//host := db.NewHost("server:3306/db")
+
+	// Connect to a different db host/port, with a username and password
+	// host := db.NewHost("username:password@server:port/db")
+
+	// Close the connection when the function returns
+	defer host.Close()
+
+	// Create a list named "greetings"
+	list, err := db.NewList(host, "greetings")
+	if err != nil {
+		log.Fatalln("Could not create list!")
+	}
+
+	// Add "hello" to the list, check if there are errors
+	if list.Add("hello") != nil {
+		log.Fatalln("Could not add an item to list!")
+	}
+
+	// Get the last item of the list
+	if item, err := list.GetLast(); err != nil {
+		log.Fatalln("Could not fetch the last item from the list!")
+	} else {
+		log.Println("The value of the stored item is:", item)
+	}
+
+	// Remove the list
+	if list.Remove() != nil {
+		log.Fatalln("Could not remove the list!")
+	}
+}
+~~~
+
+Testing
+-------
+
+A MariaDB/MySQL Database must be up and running locally for `go test` to work.
+
+Version, license and author
+---------------------------
+
+* Version: 3.2.0
+* License: MIT
+* Author: Alexander F. Rødseth &lt;xyproto@archlinux.org&gt;
+

+ 3 - 0
vendor/github.com/xyproto/simplemaria/TODO.md

@@ -0,0 +1,3 @@
+# Plans
+
+- [_] Look into using BLOBS for binary data.

+ 31 - 0
vendor/github.com/xyproto/simplemaria/creator.go

@@ -0,0 +1,31 @@
+package simplemaria
+
+import (
+	"github.com/xyproto/pinterface"
+)
+
+// For implementing pinterface.ICreator
+
+type MariaCreator struct {
+	host *Host
+}
+
+func NewCreator(host *Host) *MariaCreator {
+	return &MariaCreator{host}
+}
+
+func (m *MariaCreator) NewList(id string) (pinterface.IList, error) {
+	return NewList(m.host, id)
+}
+
+func (m *MariaCreator) NewSet(id string) (pinterface.ISet, error) {
+	return NewSet(m.host, id)
+}
+
+func (m *MariaCreator) NewHashMap(id string) (pinterface.IHashMap, error) {
+	return NewHashMap(m.host, id)
+}
+
+func (m *MariaCreator) NewKeyValue(id string) (pinterface.IKeyValue, error) {
+	return NewKeyValue(m.host, id)
+}

+ 48 - 0
vendor/github.com/xyproto/simplemaria/encdec.go

@@ -0,0 +1,48 @@
+package simplemaria
+
+import (
+	"bytes"
+	"compress/flate"
+	"encoding/hex"
+	"io/ioutil"
+)
+
+// MariaDB/MySQL does not handle some characters well.
+// Compressing and hex encoding the value is one of many possible ways
+// to avoid this. Using BLOB fields and different datatypes is another.
+func Encode(value *string) error {
+	// Don't encode empty strings
+	if *value == "" {
+		return nil
+	}
+	var buf bytes.Buffer
+	compressorWriter, err := flate.NewWriter(&buf, 1) // compression level 1 (fastest)
+	if err != nil {
+		return err
+	}
+	compressorWriter.Write([]byte(*value))
+	compressorWriter.Close()
+	*value = hex.EncodeToString(buf.Bytes())
+	return nil
+}
+
+// Dehex and decompress the given string
+func Decode(code *string) error {
+	// Don't decode empty strings
+	if *code == "" {
+		return nil
+	}
+	unhexedBytes, err := hex.DecodeString(*code)
+	if err != nil {
+		return err
+	}
+	buf := bytes.NewBuffer(unhexedBytes)
+	decompressorReader := flate.NewReader(buf)
+	decompressedBytes, err := ioutil.ReadAll(decompressorReader)
+	decompressorReader.Close()
+	if err != nil {
+		return err
+	}
+	*code = string(decompressedBytes)
+	return nil
+}

+ 10 - 0
vendor/github.com/xyproto/simplemaria/go.mod

@@ -0,0 +1,10 @@
+module github.com/xyproto/simplemaria
+
+require (
+	github.com/go-sql-driver/mysql v1.4.1
+	github.com/xyproto/cookie v0.0.0-20171003173729-8ce3defb0907
+	github.com/xyproto/pinterface v0.0.0-20181004125811-9710ef24b684
+	golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9
+	golang.org/x/net v0.0.0-20181207154023-610586996380 // indirect
+	google.golang.org/appengine v1.3.0 // indirect
+)

+ 14 - 0
vendor/github.com/xyproto/simplemaria/go.sum

@@ -0,0 +1,14 @@
+github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
+github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/xyproto/cookie v0.0.0-20171003173729-8ce3defb0907 h1:9qqWk6/29cweeD27aMqGSdk/3/Zp9/wKTQLhXfR3ix0=
+github.com/xyproto/cookie v0.0.0-20171003173729-8ce3defb0907/go.mod h1:Jkc0U5QghR0GdJHVetkXRYMciw3dGqpLR69uw8vutsY=
+github.com/xyproto/pinterface v0.0.0-20181004125811-9710ef24b684 h1:NFSurCu+HqTKLlURDwnZL2J6GQv4WKzGBuFdrO8Rimc=
+github.com/xyproto/pinterface v0.0.0-20181004125811-9710ef24b684/go.mod h1:BzQLxcJwPQpzFgOyNEL02hGO5T4VqXB1BX+lp5bE040=
+golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9 h1:mKdxBk7AujPs8kU4m80U72y/zjbZ3UcXC7dClwKbUI0=
+golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181207154023-610586996380/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+google.golang.org/appengine v1.3.0 h1:FBSsiFRMz3LBeXIomRnVzrQwSDj4ibvcRexLG0LZGQk=
+google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=

+ 145 - 0
vendor/github.com/xyproto/simplemaria/helpers.go

@@ -0,0 +1,145 @@
+package simplemaria
+
+import (
+	"log"
+	"strconv"
+	"strings"
+)
+
+var Verbose = false
+
+/* --- Helper functions --- */
+
+// Split a string into two parts, given a delimiter.
+// Returns the two parts and true if it works out.
+func twoFields(s, delim string) (string, string, bool) {
+	if strings.Count(s, delim) != 1 {
+		return s, "", false
+	}
+	fields := strings.Split(s, delim)
+	return fields[0], fields[1], true
+}
+
+func leftOf(s, delim string) string {
+	if left, _, ok := twoFields(s, delim); ok {
+		return strings.TrimSpace(left)
+	}
+	return ""
+}
+
+func rightOf(s, delim string) string {
+	if _, right, ok := twoFields(s, delim); ok {
+		return strings.TrimSpace(right)
+	}
+	return ""
+}
+
+// Parse a DSN
+func splitConnectionString(connectionString string) (string, string, bool, string, string, string) {
+	var (
+		userPass, hostPortDatabase, dbname       string
+		hostPort, password, username, port, host string
+		hasPassword                              bool
+	)
+
+	// Gather the fields
+
+	// Optional left side of @ with username and password
+	userPass = leftOf(connectionString, "@")
+	if userPass != "" {
+		hostPortDatabase = rightOf(connectionString, "@")
+	} else {
+		if strings.HasSuffix(connectionString, "@") {
+			hostPortDatabase = connectionString[:len(connectionString)-1]
+		} else {
+			hostPortDatabase = connectionString
+		}
+	}
+	// Optional right side of / with database name
+	dbname = rightOf(hostPortDatabase, "/")
+	if dbname != "" {
+		hostPort = leftOf(hostPortDatabase, "/")
+	} else {
+		if strings.HasSuffix(hostPortDatabase, "/") {
+			hostPort = hostPortDatabase[:len(hostPortDatabase)-1]
+		} else {
+			hostPort = hostPortDatabase
+		}
+		dbname = defaultDatabaseName
+	}
+	// Optional right side of : with password
+	password = rightOf(userPass, ":")
+	if password != "" {
+		username = leftOf(userPass, ":")
+	} else {
+		if strings.HasSuffix(userPass, ":") {
+			username = userPass[:len(userPass)-1]
+			hasPassword = true
+		} else {
+			username = userPass
+		}
+	}
+	// Optional right side of : with port
+	port = rightOf(hostPort, ":")
+	if port != "" {
+		host = leftOf(hostPort, ":")
+	} else {
+		if strings.HasSuffix(hostPort, ":") {
+			host = hostPort[:len(hostPort)-1]
+		} else {
+			host = hostPort
+		}
+		if host != "" {
+			port = strconv.Itoa(defaultPort)
+		}
+	}
+
+	if Verbose {
+		log.Println("Connection:")
+		log.Println("\tusername:\t", username)
+		log.Println("\tpassword:\t", password)
+		log.Println("\thas password:\t", hasPassword)
+		log.Println("\thost:\t\t", host)
+		log.Println("\tport:\t\t", port)
+		log.Println("\tdbname:\t\t", dbname)
+		log.Println()
+	}
+
+	return username, password, hasPassword, host, port, dbname
+}
+
+// Build a DSN
+func buildConnectionString(username, password string, hasPassword bool, host, port, dbname string) string {
+
+	// Build the new connection string
+
+	newConnectionString := ""
+	if (host != "") && (port != "") {
+		newConnectionString += "tcp(" + host + ":" + port + ")"
+	} else if host != "" {
+		newConnectionString += "tcp(" + host + ")"
+	} else if port != "" {
+		newConnectionString += "tcp(" + ":" + port + ")"
+		log.Fatalln("There is only a port. This should not happen.")
+	}
+	if (username != "") && hasPassword {
+		newConnectionString = username + ":" + password + "@" + newConnectionString
+	} else if username != "" {
+		newConnectionString = username + "@" + newConnectionString
+	} else if hasPassword {
+		newConnectionString = ":" + password + "@" + newConnectionString
+	}
+	newConnectionString += "/"
+
+	if Verbose {
+		log.Println("DSN:", newConnectionString)
+	}
+
+	return newConnectionString
+}
+
+// Take apart and rebuild the connection string. Also return the dbname.
+func rebuildConnectionString(connectionString string) (string, string) {
+	username, password, hasPassword, hostname, port, dbname := splitConnectionString(connectionString)
+	return buildConnectionString(username, password, hasPassword, hostname, port, dbname), dbname
+}

+ 799 - 0
vendor/github.com/xyproto/simplemaria/simplemaria.go

@@ -0,0 +1,799 @@
+// Package simplemaria offers a simple way to use a MySQL/MariaDB database.
+// This database backend is interchangeable with xyproto/simpleredis and
+// xyproto/simplebolt, since they all use xyproto/pinterface.
+package simplemaria
+
+import (
+	"database/sql"
+	"errors"
+	"fmt"
+	// Use the mysql database driver
+	_ "github.com/go-sql-driver/mysql"
+	"log"
+	"strconv"
+	"strings"
+)
+
+const (
+	// Version number. Stable API within major version numbers.
+	Version = 3.2
+)
+
+// Host represents a specific database at a database host
+type Host struct {
+	db      *sql.DB
+	dbname  string
+	rawUTF8 bool
+}
+
+// Common for each of the db datastructures used here
+type dbDatastructure struct {
+	host  *Host
+	table string
+}
+
+type (
+	List     dbDatastructure
+	Set      dbDatastructure
+	HashMap  dbDatastructure
+	KeyValue dbDatastructure
+)
+
+const (
+
+	// The default "username:password@host:port/database" that the database is running at
+	defaultDatabaseServer = ""     // "username:password@server:port/"
+	defaultDatabaseName   = "test" // "main"
+	defaultStringType     = "TEXT" // "VARCHAR(65535)"
+	defaultPort           = 3306
+
+	// Requires MySQL >= 5.53 and MariaDB >= ? for utf8mb4
+	charset = "utf8mb4" // "utf8"
+
+	// Column names
+	listCol  = "a_list"
+	setCol   = "a_set"
+	keyCol   = "property"
+	valCol   = "value"
+	ownerCol = "owner"
+)
+
+// Test if the local database server is up and running.
+func TestConnection() (err error) {
+	return TestConnectionHost(defaultDatabaseServer)
+}
+
+// Test if a given database server is up and running.
+// connectionString may be on the form "username:password@host:port/database".
+func TestConnectionHost(connectionString string) (err error) {
+	newConnectionString, _ := rebuildConnectionString(connectionString)
+	// Connect to the given host:port
+	db, err := sql.Open("mysql", newConnectionString)
+	if err != nil {
+		return err
+	}
+	defer db.Close()
+	err = db.Ping()
+	if Verbose {
+		if err != nil {
+			log.Println("Ping: failed")
+		} else {
+			log.Println("Ping: ok")
+		}
+	}
+	return err
+}
+
+// Test if a given database server is up and running.
+func TestConnectionHostWithDSN(connectionString string) (err error) {
+	// Connect to the given host:port
+	db, err := sql.Open("mysql", connectionString)
+	if err != nil {
+		return err
+	}
+	defer db.Close()
+	err = db.Ping()
+	if Verbose {
+		if err != nil {
+			log.Println("Ping: failed")
+		} else {
+			log.Println("Ping: ok")
+		}
+	}
+	return err
+}
+
+/* --- Host functions --- */
+
+// Create a new database connection.
+// connectionString may be on the form "username:password@host:port/database".
+func NewHost(connectionString string) *Host {
+
+	newConnectionString, dbname := rebuildConnectionString(connectionString)
+
+	db, err := sql.Open("mysql", newConnectionString)
+	if err != nil {
+		log.Fatalln("Could not connect to " + newConnectionString + "!")
+	}
+	host := &Host{db, dbname, false}
+	if err := host.Ping(); err != nil {
+		log.Fatalln("Host does not reply to ping: " + err.Error())
+	}
+	if err := host.createDatabase(); err != nil {
+		log.Fatalln("Could not create database " + host.dbname + ": " + err.Error())
+	}
+	if err := host.useDatabase(); err != nil {
+		panic("Could not use database " + host.dbname + ": " + err.Error())
+	}
+	return host
+}
+
+// Create a new database connection with a valid DSN.
+func NewHostWithDSN(connectionString string, dbname string) *Host {
+
+	db, err := sql.Open("mysql", connectionString)
+	if err != nil {
+		log.Fatalln("Could not connect to " + connectionString + "!")
+	}
+	host := &Host{db, dbname, false}
+	if err := host.Ping(); err != nil {
+		log.Fatalln("Host does not reply to ping: " + err.Error())
+	}
+	if err := host.createDatabase(); err != nil {
+		log.Fatalln("Could not create database " + host.dbname + ": " + err.Error())
+	}
+	if err := host.useDatabase(); err != nil {
+		panic("Could not use database " + host.dbname + ": " + err.Error())
+	}
+	return host
+}
+
+// The default database connection
+func New() *Host {
+	connectionString := defaultDatabaseServer + defaultDatabaseName
+	if !strings.HasSuffix(defaultDatabaseServer, "/") {
+		connectionString = defaultDatabaseServer + "/" + defaultDatabaseName
+	}
+	return NewHost(connectionString)
+}
+
+// Should the UTF-8 data be raw, and not hex encoded and compressed?
+func (host *Host) SetRawUTF8(enabled bool) {
+	host.rawUTF8 = enabled
+}
+
+// Select a different database. Create the database if needed.
+func (host *Host) SelectDatabase(dbname string) error {
+	host.dbname = dbname
+	if err := host.createDatabase(); err != nil {
+		return err
+	}
+	if err := host.useDatabase(); err != nil {
+		return err
+	}
+	return nil
+}
+
+// Will create the database if it does not already exist
+func (host *Host) createDatabase() error {
+	if _, err := host.db.Exec("CREATE DATABASE IF NOT EXISTS " + host.dbname + " CHARACTER SET = " + charset); err != nil {
+		return err
+	}
+	if Verbose {
+		log.Println("Created database " + host.dbname)
+	}
+	return nil
+}
+
+// Use the host.dbname database
+func (host *Host) useDatabase() error {
+	if _, err := host.db.Exec("USE " + host.dbname); err != nil {
+		return err
+	}
+	if Verbose {
+		log.Println("Using database " + host.dbname)
+	}
+	return nil
+}
+
+// Close the connection
+func (host *Host) Close() {
+	host.db.Close()
+}
+
+// Ping the host
+func (host *Host) Ping() error {
+	return host.db.Ping()
+}
+
+/* --- List functions --- */
+
+// Create a new list. Lists are ordered.
+func NewList(host *Host, name string) (*List, error) {
+	l := &List{host, name}
+	if _, err := l.host.db.Exec("CREATE TABLE IF NOT EXISTS " + name + " (id INT PRIMARY KEY AUTO_INCREMENT, " + listCol + " " + defaultStringType + ")"); err != nil {
+		return nil, err
+	}
+	if Verbose {
+		log.Println("Created table " + name + " in database " + host.dbname)
+	}
+	return l, nil
+}
+
+// Add an element to the list
+func (l *List) Add(value string) error {
+	if !l.host.rawUTF8 {
+		Encode(&value)
+	}
+	_, err := l.host.db.Exec("INSERT INTO "+l.table+" ("+listCol+") VALUES (?)", value)
+	return err
+}
+
+// Get all elements of a list
+func (l *List) All() ([]string, error) {
+	rows, err := l.host.db.Query("SELECT " + listCol + " FROM " + l.table + " ORDER BY id")
+	if err != nil {
+		return []string{}, err
+	}
+	defer rows.Close()
+	var (
+		values []string
+		value  string
+	)
+	for rows.Next() {
+		err = rows.Scan(&value)
+		if !l.host.rawUTF8 {
+			Decode(&value)
+		}
+		values = append(values, value)
+		if err != nil {
+			// Unusual, worthy of panic
+			panic(err.Error())
+		}
+	}
+	if err := rows.Err(); err != nil {
+		// Unusual, worthy of panic
+		panic(err.Error())
+	}
+	return values, nil
+}
+
+// Deprecated, please use .All() instead
+func (l *List) GetAll() ([]string, error) {
+	return l.All()
+}
+
+// Get the last element of a list
+func (l *List) Last() (string, error) {
+	// Fetches the item with the largest id.
+	// Faster than "ORDER BY id DESC limit 1" for large tables.
+	rows, err := l.host.db.Query("SELECT " + listCol + " FROM " + l.table + " WHERE id = (SELECT MAX(id) FROM " + l.table + ")")
+	if err != nil {
+		return "", err
+	}
+	defer rows.Close()
+	var value string
+	// Get the value. Will only loop once.
+	for rows.Next() {
+		err = rows.Scan(&value)
+		if err != nil {
+			// Unusual, worthy of panic
+			panic(err.Error())
+		}
+	}
+	if err := rows.Err(); err != nil {
+		// Unusual, worthy of panic
+		panic(err.Error())
+	}
+	if !l.host.rawUTF8 {
+		Decode(&value)
+	}
+	return value, nil
+}
+
+// Deprecated, please use .Last() instead
+func (l *List) GetLast() (string, error) {
+	return l.Last()
+}
+
+// Get the last N elements of a list
+func (l *List) LastN(n int) ([]string, error) {
+	rows, err := l.host.db.Query("SELECT " + listCol + " FROM (SELECT * FROM " + l.table + " ORDER BY id DESC limit " + strconv.Itoa(n) + ")sub ORDER BY id ASC")
+	if err != nil {
+		return []string{}, err
+	}
+	defer rows.Close()
+	var (
+		values []string
+		value  string
+	)
+	for rows.Next() {
+		err = rows.Scan(&value)
+		if !l.host.rawUTF8 {
+			Decode(&value)
+		}
+		values = append(values, value)
+		if err != nil {
+			// Unusual, worthy of panic
+			panic(err.Error())
+		}
+	}
+	if err := rows.Err(); err != nil {
+		// Unusual, worthy of panic
+		panic(err.Error())
+	}
+	if len(values) < n {
+		return []string{}, errors.New("Too few elements in table at GetLastN")
+	}
+	return values, nil
+}
+
+// Deprecated, please use .LastN(n) instead
+func (l *List) GetLastN(n int) ([]string, error) {
+	return l.LastN(n)
+}
+
+// Remove this list
+func (l *List) Remove() error {
+	// Remove the table
+	_, err := l.host.db.Exec("DROP TABLE " + l.table)
+	return err
+}
+
+// Clear the list contents
+func (l *List) Clear() error {
+	// Clear the table
+	_, err := l.host.db.Exec("TRUNCATE TABLE " + l.table)
+	return err
+}
+
+/* --- Set functions --- */
+
+// Create a new set
+func NewSet(host *Host, name string) (*Set, error) {
+	s := &Set{host, name}
+	if _, err := s.host.db.Exec("CREATE TABLE IF NOT EXISTS " + name + " (" + setCol + " " + defaultStringType + ")"); err != nil {
+		return nil, err
+	}
+	if Verbose {
+		log.Println("Created table " + name + " in database " + host.dbname)
+	}
+	return s, nil
+}
+
+// Add an element to the set
+func (s *Set) Add(value string) error {
+	originalValue := value
+	if !s.host.rawUTF8 {
+		Encode(&value)
+	}
+	// Check if the value is not already there before adding
+	has, err := s.Has(originalValue)
+	if !has && (err == nil) {
+		_, err = s.host.db.Exec("INSERT INTO "+s.table+" ("+setCol+") VALUES (?)", value)
+	}
+	return err
+}
+
+// Check if a given value is in the set
+func (s *Set) Has(value string) (bool, error) {
+	if !s.host.rawUTF8 {
+		Encode(&value)
+	}
+	rows, err := s.host.db.Query("SELECT "+setCol+" FROM "+s.table+" WHERE "+setCol+" = ?", value)
+	if err != nil {
+		return false, err
+	}
+	defer rows.Close()
+	var scanValue string
+	// Get the value. Should not loop more than once.
+	counter := 0
+	for rows.Next() {
+		err = rows.Scan(&scanValue)
+		if err != nil {
+			// Unusual, worthy of panic
+			panic(err.Error())
+		}
+		counter++
+	}
+	if err := rows.Err(); err != nil {
+		// Unusual, worthy of panic
+		panic(err.Error())
+	}
+	if counter > 1 {
+		panic("Duplicate members in set! " + value)
+	}
+	return counter > 0, nil
+}
+
+// Get all elements of the set
+func (s *Set) All() ([]string, error) {
+	rows, err := s.host.db.Query("SELECT " + setCol + " FROM " + s.table)
+	if err != nil {
+		return []string{}, err
+	}
+	defer rows.Close()
+	var (
+		values []string
+		value  string
+	)
+	for rows.Next() {
+		err = rows.Scan(&value)
+		if !s.host.rawUTF8 {
+			Decode(&value)
+		}
+		values = append(values, value)
+		if err != nil {
+			// Unusual, worthy of panic
+			panic(err.Error())
+		}
+	}
+	if err := rows.Err(); err != nil {
+		// Unusual, worthy of panic
+		panic(err.Error())
+	}
+	return values, nil
+}
+
+// Deprecated, please use .All() instead
+func (s *Set) GetAll() ([]string, error) {
+	return s.All()
+}
+
+// Remove an element from the set
+func (s *Set) Del(value string) error {
+	if !s.host.rawUTF8 {
+		Encode(&value)
+	}
+	// Remove a value from the table
+	_, err := s.host.db.Exec("DELETE FROM "+s.table+" WHERE "+setCol+" = ?", value)
+	return err
+}
+
+// Remove this set
+func (s *Set) Remove() error {
+	// Remove the table
+	_, err := s.host.db.Exec("DROP TABLE " + s.table)
+	return err
+}
+
+// Clear the list contents
+func (s *Set) Clear() error {
+	// Clear the table
+	_, err := s.host.db.Exec("TRUNCATE TABLE " + s.table)
+	return err
+}
+
+/* --- HashMap functions --- */
+
+// Create a new hashmap
+func NewHashMap(host *Host, name string) (*HashMap, error) {
+	h := &HashMap{host, name}
+	// Using three columns: element id, key and value
+	query := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s (%s %s, %s %s, %s %s)", name, ownerCol, defaultStringType, keyCol, defaultStringType, valCol, defaultStringType)
+	if _, err := h.host.db.Exec(query); err != nil {
+		return nil, err
+	}
+	if Verbose {
+		log.Println("Created table " + name + " in database " + host.dbname)
+	}
+	return h, nil
+}
+
+// Set a value in a hashmap given the element id (for instance a user id) and the key (for instance "password")
+func (h *HashMap) Set(owner, key, value string) error {
+	if !h.host.rawUTF8 {
+		Encode(&value)
+	}
+	// See if the owner and key already exists
+	ok, err := h.Has(owner, key)
+	if err != nil {
+		return err
+	}
+	if Verbose {
+		log.Printf("%s/%s exists? %v\n", owner, key, ok)
+	}
+	if ok {
+		_, err = h.host.db.Exec("UPDATE "+h.table+" SET "+valCol+" = ? WHERE "+ownerCol+" = ? AND "+keyCol+" = ?", value, owner, key)
+		if Verbose {
+			log.Println("Updated the table: " + h.table)
+		}
+	} else {
+		_, err = h.host.db.Exec("INSERT INTO "+h.table+" ("+ownerCol+", "+keyCol+", "+valCol+") VALUES (?, ?, ?)", owner, key, value)
+		if Verbose {
+			log.Println("Added to the table: " + h.table)
+		}
+	}
+	return err
+}
+
+// Get a value from a hashmap given the element id (for instance a user id) and the key (for instance "password").
+func (h *HashMap) Get(owner, key string) (string, error) {
+	rows, err := h.host.db.Query("SELECT "+valCol+" FROM "+h.table+" WHERE "+ownerCol+" = ? AND "+keyCol+" = ?", owner, key)
+	if err != nil {
+		return "", err
+	}
+	defer rows.Close()
+	var value string
+	// Get the value. Should only loop once.
+	counter := 0
+	for rows.Next() {
+		err = rows.Scan(&value)
+		if err != nil {
+			// Unusual, worthy of panic
+			panic(err.Error())
+		}
+		counter++
+	}
+	if err := rows.Err(); err != nil {
+		// Unusual, worthy of panic
+		panic(err.Error())
+	}
+	if counter == 0 {
+		return "", errors.New("No such owner/key: " + owner + "/" + key)
+	}
+	if !h.host.rawUTF8 {
+		Decode(&value)
+	}
+	return value, nil
+}
+
+// Check if a given owner + key is in the hash map
+func (h *HashMap) Has(owner, key string) (bool, error) {
+	rows, err := h.host.db.Query("SELECT "+valCol+" FROM "+h.table+" WHERE "+ownerCol+" = ? AND "+keyCol+" = ?", owner, key)
+	if err != nil {
+		return false, err
+	}
+	defer rows.Close()
+	var value string
+	// Get the value. Should only loop once.
+	counter := 0
+	for rows.Next() {
+		err = rows.Scan(&value)
+		if err != nil {
+			// Unusual, worthy of panic
+			panic(err.Error())
+		}
+		counter++
+	}
+	if err := rows.Err(); err != nil {
+		// Unusual, worthy of panic
+		panic(err.Error())
+	}
+	if counter > 1 {
+		panic("Duplicate keys in hash map! " + value)
+	}
+	return counter > 0, nil
+}
+
+// Check if a given owner exists as a hash map at all
+func (h *HashMap) Exists(owner string) (bool, error) {
+	rows, err := h.host.db.Query("SELECT "+valCol+" FROM "+h.table+" WHERE "+ownerCol+" = ?", owner)
+	if err != nil {
+		return false, err
+	}
+	defer rows.Close()
+	var value string
+	// Get the value. Should only loop once.
+	counter := 0
+	for rows.Next() {
+		err = rows.Scan(&value)
+		if err != nil {
+			// Unusual, worthy of panic
+			panic(err.Error())
+		}
+		counter++
+	}
+	if err := rows.Err(); err != nil {
+		// Unusual, worthy of panic
+		panic(err.Error())
+	}
+	return counter > 0, nil
+}
+
+// Get all owners (not keys, not values) for all hash elements
+func (h *HashMap) All() ([]string, error) {
+	rows, err := h.host.db.Query("SELECT " + ownerCol + " FROM " + h.table)
+	if err != nil {
+		return []string{}, err
+	}
+	defer rows.Close()
+	var (
+		values []string
+		value  string
+	)
+	for rows.Next() {
+		err = rows.Scan(&value)
+		values = append(values, value)
+		if err != nil {
+			// Unusual, worthy of panic
+			panic(err.Error())
+		}
+	}
+	if err := rows.Err(); err != nil {
+		// Unusual, worthy of panic
+		panic(err.Error())
+	}
+	return values, nil
+}
+
+// Deprecated, please use .All() instead
+func (h *HashMap) GetAll() ([]string, error) {
+	return h.All()
+}
+
+// Get all keys for a given owner
+func (h *HashMap) Keys(owner string) ([]string, error) {
+	rows, err := h.host.db.Query("SELECT "+keyCol+" FROM "+h.table+" WHERE "+ownerCol+"= ?", owner)
+	if err != nil {
+		return []string{}, err
+	}
+	defer rows.Close()
+	var (
+		values []string
+		value  string
+	)
+	for rows.Next() {
+		err = rows.Scan(&value)
+		values = append(values, value)
+		if err != nil {
+			// Unusual, worthy of panic
+			panic(err.Error())
+		}
+	}
+	if err := rows.Err(); err != nil {
+		// Unusual, worthy of panic
+		panic(err.Error())
+	}
+	return values, nil
+}
+
+// Remove a key for an entry in a hashmap (for instance the email field for a user)
+func (h *HashMap) DelKey(owner, key string) error {
+	// Remove a key from the hashmap
+	_, err := h.host.db.Exec("DELETE FROM "+h.table+" WHERE "+ownerCol+" = ? AND "+keyCol+" = ?", owner, key)
+	return err
+}
+
+// Remove an element (for instance a user)
+func (h *HashMap) Del(owner string) error {
+	// Remove an element id from the table
+	results, err := h.host.db.Exec("DELETE FROM "+h.table+" WHERE "+ownerCol+" = ?", owner)
+	if err != nil {
+		return err
+	}
+	n, err := results.RowsAffected()
+	if err != nil {
+		return err
+	}
+	if Verbose {
+		log.Println(n, "rows were deleted with Del("+owner+")!")
+	}
+	return nil
+}
+
+// Remove this hashmap
+func (h *HashMap) Remove() error {
+	// Remove the table
+	_, err := h.host.db.Exec("DROP TABLE " + h.table)
+	return err
+}
+
+// Clear the contents
+func (h *HashMap) Clear() error {
+	// Clear the table
+	_, err := h.host.db.Exec("TRUNCATE TABLE " + h.table)
+	return err
+}
+
+/* --- KeyValue functions --- */
+
+// Create a new key/value
+func NewKeyValue(host *Host, name string) (*KeyValue, error) {
+	kv := &KeyValue{host, name}
+	query := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s (%s %s, %s %s)", name, keyCol, defaultStringType, valCol, defaultStringType)
+	if _, err := kv.host.db.Exec(query); err != nil {
+		return nil, err
+	}
+	if Verbose {
+		log.Println("Created table " + name + " in database " + host.dbname)
+	}
+	return kv, nil
+
+}
+
+// Set a key and value
+func (kv *KeyValue) Set(key, value string) error {
+	if !kv.host.rawUTF8 {
+		Encode(&value)
+	}
+	if _, err := kv.Get(key); err != nil {
+		// Key does not exist, create it
+		_, err = kv.host.db.Exec("INSERT INTO "+kv.table+" ("+keyCol+", "+valCol+") VALUES (?, ?)", key, value)
+		return err
+	}
+	// Key exists, update the value
+	_, err := kv.host.db.Exec("UPDATE "+kv.table+" SET "+valCol+" = ? WHERE "+keyCol+" = ?", value, key)
+	return err
+}
+
+// Get a value given a key
+func (kv *KeyValue) Get(key string) (string, error) {
+	rows, err := kv.host.db.Query("SELECT "+valCol+" FROM "+kv.table+" WHERE "+keyCol+" = ?", key)
+	if err != nil {
+		return "", err
+	}
+	defer rows.Close()
+	var value string
+	// Get the value. Should only loop once.
+	counter := 0
+	for rows.Next() {
+		err = rows.Scan(&value)
+		if err != nil {
+			// Unusual, worthy of panic
+			panic(err.Error())
+		}
+		counter++
+	}
+	if err := rows.Err(); err != nil {
+		// Unusual, worthy of panic
+		panic(err.Error())
+	}
+	if counter != 1 {
+		return "", errors.New("Wrong number of keys in KeyValue table: " + kv.table)
+	}
+	if !kv.host.rawUTF8 {
+		Decode(&value)
+	}
+	return value, nil
+}
+
+// Increase the value of a key, returns the new value
+// Returns an empty string if there were errors,
+// or "0" if the key does not already exist.
+func (kv *KeyValue) Inc(key string) (string, error) {
+	// Retreieve the current value, if any
+	num := 0
+	// See if we can fetch an existing value. NOTE: "== nil"
+	if val, err := kv.Get(key); err == nil {
+		// See if we can convert the value to a number. NOTE: "== nil"
+		if converted, err2 := strconv.Atoi(val); err2 == nil {
+			num = converted
+		}
+	} else {
+		// The key does not exist, create a new one.
+		// This is to reflect the behavior of INCR in Redis.
+		NewKeyValue(kv.host, kv.table)
+	}
+	// Num is now either 0 or the previous numeric value
+	num++
+	// Convert the new value to a string
+	val := strconv.Itoa(num)
+	// Store the new number
+	if err := kv.Set(key, val); err != nil {
+		// Saving the value failed
+		return "0", err
+	}
+	// Success
+	return val, nil
+}
+
+// Remove a key
+func (kv *KeyValue) Del(key string) error {
+	_, err := kv.host.db.Exec("DELETE FROM "+kv.table+" WHERE "+keyCol+" = ?", key)
+	return err
+}
+
+// Remove this key/value
+func (kv *KeyValue) Remove() error {
+	// Remove the table
+	_, err := kv.host.db.Exec("DROP TABLE " + kv.table)
+	return err
+}
+
+// Clear this key/value
+func (kv *KeyValue) Clear() error {
+	// Remove the table
+	_, err := kv.host.db.Exec("TRUNCATE TABLE " + kv.table)
+	return err
+}

+ 35 - 0
vendor/golang.org/x/crypto/bcrypt/base64.go

@@ -0,0 +1,35 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bcrypt
+
+import "encoding/base64"
+
+const alphabet = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
+
+var bcEncoding = base64.NewEncoding(alphabet)
+
+func base64Encode(src []byte) []byte {
+	n := bcEncoding.EncodedLen(len(src))
+	dst := make([]byte, n)
+	bcEncoding.Encode(dst, src)
+	for dst[n-1] == '=' {
+		n--
+	}
+	return dst[:n]
+}
+
+func base64Decode(src []byte) ([]byte, error) {
+	numOfEquals := 4 - (len(src) % 4)
+	for i := 0; i < numOfEquals; i++ {
+		src = append(src, '=')
+	}
+
+	dst := make([]byte, bcEncoding.DecodedLen(len(src)))
+	n, err := bcEncoding.Decode(dst, src)
+	if err != nil {
+		return nil, err
+	}
+	return dst[:n], nil
+}

+ 295 - 0
vendor/golang.org/x/crypto/bcrypt/bcrypt.go

@@ -0,0 +1,295 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package bcrypt implements Provos and Mazières's bcrypt adaptive hashing
+// algorithm. See http://www.usenix.org/event/usenix99/provos/provos.pdf
+package bcrypt // import "golang.org/x/crypto/bcrypt"
+
+// The code is a port of Provos and Mazières's C implementation.
+import (
+	"crypto/rand"
+	"crypto/subtle"
+	"errors"
+	"fmt"
+	"io"
+	"strconv"
+
+	"golang.org/x/crypto/blowfish"
+)
+
+const (
+	MinCost     int = 4  // the minimum allowable cost as passed in to GenerateFromPassword
+	MaxCost     int = 31 // the maximum allowable cost as passed in to GenerateFromPassword
+	DefaultCost int = 10 // the cost that will actually be set if a cost below MinCost is passed into GenerateFromPassword
+)
+
+// The error returned from CompareHashAndPassword when a password and hash do
+// not match.
+var ErrMismatchedHashAndPassword = errors.New("crypto/bcrypt: hashedPassword is not the hash of the given password")
+
+// The error returned from CompareHashAndPassword when a hash is too short to
+// be a bcrypt hash.
+var ErrHashTooShort = errors.New("crypto/bcrypt: hashedSecret too short to be a bcrypted password")
+
+// The error returned from CompareHashAndPassword when a hash was created with
+// a bcrypt algorithm newer than this implementation.
+type HashVersionTooNewError byte
+
+func (hv HashVersionTooNewError) Error() string {
+	return fmt.Sprintf("crypto/bcrypt: bcrypt algorithm version '%c' requested is newer than current version '%c'", byte(hv), majorVersion)
+}
+
+// The error returned from CompareHashAndPassword when a hash starts with something other than '$'
+type InvalidHashPrefixError byte
+
+func (ih InvalidHashPrefixError) Error() string {
+	return fmt.Sprintf("crypto/bcrypt: bcrypt hashes must start with '$', but hashedSecret started with '%c'", byte(ih))
+}
+
+type InvalidCostError int
+
+func (ic InvalidCostError) Error() string {
+	return fmt.Sprintf("crypto/bcrypt: cost %d is outside allowed range (%d,%d)", int(ic), int(MinCost), int(MaxCost))
+}
+
+const (
+	majorVersion       = '2'
+	minorVersion       = 'a'
+	maxSaltSize        = 16
+	maxCryptedHashSize = 23
+	encodedSaltSize    = 22
+	encodedHashSize    = 31
+	minHashSize        = 59
+)
+
+// magicCipherData is an IV for the 64 Blowfish encryption calls in
+// bcrypt(). It's the string "OrpheanBeholderScryDoubt" in big-endian bytes.
+var magicCipherData = []byte{
+	0x4f, 0x72, 0x70, 0x68,
+	0x65, 0x61, 0x6e, 0x42,
+	0x65, 0x68, 0x6f, 0x6c,
+	0x64, 0x65, 0x72, 0x53,
+	0x63, 0x72, 0x79, 0x44,
+	0x6f, 0x75, 0x62, 0x74,
+}
+
+type hashed struct {
+	hash  []byte
+	salt  []byte
+	cost  int // allowed range is MinCost to MaxCost
+	major byte
+	minor byte
+}
+
+// GenerateFromPassword returns the bcrypt hash of the password at the given
+// cost. If the cost given is less than MinCost, the cost will be set to
+// DefaultCost, instead. Use CompareHashAndPassword, as defined in this package,
+// to compare the returned hashed password with its cleartext version.
+func GenerateFromPassword(password []byte, cost int) ([]byte, error) {
+	p, err := newFromPassword(password, cost)
+	if err != nil {
+		return nil, err
+	}
+	return p.Hash(), nil
+}
+
+// CompareHashAndPassword compares a bcrypt hashed password with its possible
+// plaintext equivalent. Returns nil on success, or an error on failure.
+func CompareHashAndPassword(hashedPassword, password []byte) error {
+	p, err := newFromHash(hashedPassword)
+	if err != nil {
+		return err
+	}
+
+	otherHash, err := bcrypt(password, p.cost, p.salt)
+	if err != nil {
+		return err
+	}
+
+	otherP := &hashed{otherHash, p.salt, p.cost, p.major, p.minor}
+	if subtle.ConstantTimeCompare(p.Hash(), otherP.Hash()) == 1 {
+		return nil
+	}
+
+	return ErrMismatchedHashAndPassword
+}
+
+// Cost returns the hashing cost used to create the given hashed
+// password. When, in the future, the hashing cost of a password system needs
+// to be increased in order to adjust for greater computational power, this
+// function allows one to establish which passwords need to be updated.
+func Cost(hashedPassword []byte) (int, error) {
+	p, err := newFromHash(hashedPassword)
+	if err != nil {
+		return 0, err
+	}
+	return p.cost, nil
+}
+
+func newFromPassword(password []byte, cost int) (*hashed, error) {
+	if cost < MinCost {
+		cost = DefaultCost
+	}
+	p := new(hashed)
+	p.major = majorVersion
+	p.minor = minorVersion
+
+	err := checkCost(cost)
+	if err != nil {
+		return nil, err
+	}
+	p.cost = cost
+
+	unencodedSalt := make([]byte, maxSaltSize)
+	_, err = io.ReadFull(rand.Reader, unencodedSalt)
+	if err != nil {
+		return nil, err
+	}
+
+	p.salt = base64Encode(unencodedSalt)
+	hash, err := bcrypt(password, p.cost, p.salt)
+	if err != nil {
+		return nil, err
+	}
+	p.hash = hash
+	return p, err
+}
+
+func newFromHash(hashedSecret []byte) (*hashed, error) {
+	if len(hashedSecret) < minHashSize {
+		return nil, ErrHashTooShort
+	}
+	p := new(hashed)
+	n, err := p.decodeVersion(hashedSecret)
+	if err != nil {
+		return nil, err
+	}
+	hashedSecret = hashedSecret[n:]
+	n, err = p.decodeCost(hashedSecret)
+	if err != nil {
+		return nil, err
+	}
+	hashedSecret = hashedSecret[n:]
+
+	// The "+2" is here because we'll have to append at most 2 '=' to the salt
+	// when base64 decoding it in expensiveBlowfishSetup().
+	p.salt = make([]byte, encodedSaltSize, encodedSaltSize+2)
+	copy(p.salt, hashedSecret[:encodedSaltSize])
+
+	hashedSecret = hashedSecret[encodedSaltSize:]
+	p.hash = make([]byte, len(hashedSecret))
+	copy(p.hash, hashedSecret)
+
+	return p, nil
+}
+
+func bcrypt(password []byte, cost int, salt []byte) ([]byte, error) {
+	cipherData := make([]byte, len(magicCipherData))
+	copy(cipherData, magicCipherData)
+
+	c, err := expensiveBlowfishSetup(password, uint32(cost), salt)
+	if err != nil {
+		return nil, err
+	}
+
+	for i := 0; i < 24; i += 8 {
+		for j := 0; j < 64; j++ {
+			c.Encrypt(cipherData[i:i+8], cipherData[i:i+8])
+		}
+	}
+
+	// Bug compatibility with C bcrypt implementations. We only encode 23 of
+	// the 24 bytes encrypted.
+	hsh := base64Encode(cipherData[:maxCryptedHashSize])
+	return hsh, nil
+}
+
+func expensiveBlowfishSetup(key []byte, cost uint32, salt []byte) (*blowfish.Cipher, error) {
+	csalt, err := base64Decode(salt)
+	if err != nil {
+		return nil, err
+	}
+
+	// Bug compatibility with C bcrypt implementations. They use the trailing
+	// NULL in the key string during expansion.
+	// We copy the key to prevent changing the underlying array.
+	ckey := append(key[:len(key):len(key)], 0)
+
+	c, err := blowfish.NewSaltedCipher(ckey, csalt)
+	if err != nil {
+		return nil, err
+	}
+
+	var i, rounds uint64
+	rounds = 1 << cost
+	for i = 0; i < rounds; i++ {
+		blowfish.ExpandKey(ckey, c)
+		blowfish.ExpandKey(csalt, c)
+	}
+
+	return c, nil
+}
+
+func (p *hashed) Hash() []byte {
+	arr := make([]byte, 60)
+	arr[0] = '$'
+	arr[1] = p.major
+	n := 2
+	if p.minor != 0 {
+		arr[2] = p.minor
+		n = 3
+	}
+	arr[n] = '$'
+	n++
+	copy(arr[n:], []byte(fmt.Sprintf("%02d", p.cost)))
+	n += 2
+	arr[n] = '$'
+	n++
+	copy(arr[n:], p.salt)
+	n += encodedSaltSize
+	copy(arr[n:], p.hash)
+	n += encodedHashSize
+	return arr[:n]
+}
+
+func (p *hashed) decodeVersion(sbytes []byte) (int, error) {
+	if sbytes[0] != '$' {
+		return -1, InvalidHashPrefixError(sbytes[0])
+	}
+	if sbytes[1] > majorVersion {
+		return -1, HashVersionTooNewError(sbytes[1])
+	}
+	p.major = sbytes[1]
+	n := 3
+	if sbytes[2] != '$' {
+		p.minor = sbytes[2]
+		n++
+	}
+	return n, nil
+}
+
+// sbytes should begin where decodeVersion left off.
+func (p *hashed) decodeCost(sbytes []byte) (int, error) {
+	cost, err := strconv.Atoi(string(sbytes[0:2]))
+	if err != nil {
+		return -1, err
+	}
+	err = checkCost(cost)
+	if err != nil {
+		return -1, err
+	}
+	p.cost = cost
+	return 3, nil
+}
+
+func (p *hashed) String() string {
+	return fmt.Sprintf("&{hash: %#v, salt: %#v, cost: %d, major: %c, minor: %c}", string(p.hash), p.salt, p.cost, p.major, p.minor)
+}
+
+func checkCost(cost int) error {
+	if cost < MinCost || cost > MaxCost {
+		return InvalidCostError(cost)
+	}
+	return nil
+}

+ 159 - 0
vendor/golang.org/x/crypto/blowfish/block.go

@@ -0,0 +1,159 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package blowfish
+
+// getNextWord returns the next big-endian uint32 value from the byte slice
+// at the given position in a circular manner, updating the position.
+func getNextWord(b []byte, pos *int) uint32 {
+	var w uint32
+	j := *pos
+	for i := 0; i < 4; i++ {
+		w = w<<8 | uint32(b[j])
+		j++
+		if j >= len(b) {
+			j = 0
+		}
+	}
+	*pos = j
+	return w
+}
+
+// ExpandKey performs a key expansion on the given *Cipher. Specifically, it
+// performs the Blowfish algorithm's key schedule which sets up the *Cipher's
+// pi and substitution tables for calls to Encrypt. This is used, primarily,
+// by the bcrypt package to reuse the Blowfish key schedule during its
+// set up. It's unlikely that you need to use this directly.
+func ExpandKey(key []byte, c *Cipher) {
+	j := 0
+	for i := 0; i < 18; i++ {
+		// Using inlined getNextWord for performance.
+		var d uint32
+		for k := 0; k < 4; k++ {
+			d = d<<8 | uint32(key[j])
+			j++
+			if j >= len(key) {
+				j = 0
+			}
+		}
+		c.p[i] ^= d
+	}
+
+	var l, r uint32
+	for i := 0; i < 18; i += 2 {
+		l, r = encryptBlock(l, r, c)
+		c.p[i], c.p[i+1] = l, r
+	}
+
+	for i := 0; i < 256; i += 2 {
+		l, r = encryptBlock(l, r, c)
+		c.s0[i], c.s0[i+1] = l, r
+	}
+	for i := 0; i < 256; i += 2 {
+		l, r = encryptBlock(l, r, c)
+		c.s1[i], c.s1[i+1] = l, r
+	}
+	for i := 0; i < 256; i += 2 {
+		l, r = encryptBlock(l, r, c)
+		c.s2[i], c.s2[i+1] = l, r
+	}
+	for i := 0; i < 256; i += 2 {
+		l, r = encryptBlock(l, r, c)
+		c.s3[i], c.s3[i+1] = l, r
+	}
+}
+
+// This is similar to ExpandKey, but folds the salt during the key
+// schedule. While ExpandKey is essentially expandKeyWithSalt with an all-zero
+// salt passed in, reusing ExpandKey turns out to be a place of inefficiency
+// and specializing it here is useful.
+func expandKeyWithSalt(key []byte, salt []byte, c *Cipher) {
+	j := 0
+	for i := 0; i < 18; i++ {
+		c.p[i] ^= getNextWord(key, &j)
+	}
+
+	j = 0
+	var l, r uint32
+	for i := 0; i < 18; i += 2 {
+		l ^= getNextWord(salt, &j)
+		r ^= getNextWord(salt, &j)
+		l, r = encryptBlock(l, r, c)
+		c.p[i], c.p[i+1] = l, r
+	}
+
+	for i := 0; i < 256; i += 2 {
+		l ^= getNextWord(salt, &j)
+		r ^= getNextWord(salt, &j)
+		l, r = encryptBlock(l, r, c)
+		c.s0[i], c.s0[i+1] = l, r
+	}
+
+	for i := 0; i < 256; i += 2 {
+		l ^= getNextWord(salt, &j)
+		r ^= getNextWord(salt, &j)
+		l, r = encryptBlock(l, r, c)
+		c.s1[i], c.s1[i+1] = l, r
+	}
+
+	for i := 0; i < 256; i += 2 {
+		l ^= getNextWord(salt, &j)
+		r ^= getNextWord(salt, &j)
+		l, r = encryptBlock(l, r, c)
+		c.s2[i], c.s2[i+1] = l, r
+	}
+
+	for i := 0; i < 256; i += 2 {
+		l ^= getNextWord(salt, &j)
+		r ^= getNextWord(salt, &j)
+		l, r = encryptBlock(l, r, c)
+		c.s3[i], c.s3[i+1] = l, r
+	}
+}
+
+func encryptBlock(l, r uint32, c *Cipher) (uint32, uint32) {
+	xl, xr := l, r
+	xl ^= c.p[0]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[1]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[2]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[3]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[4]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[5]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[6]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[7]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[8]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[9]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[10]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[11]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[12]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[13]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[14]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[15]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[16]
+	xr ^= c.p[17]
+	return xr, xl
+}
+
+func decryptBlock(l, r uint32, c *Cipher) (uint32, uint32) {
+	xl, xr := l, r
+	xl ^= c.p[17]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[16]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[15]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[14]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[13]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[12]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[11]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[10]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[9]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[8]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[7]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[6]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[5]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[4]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[3]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[2]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[1]
+	xr ^= c.p[0]
+	return xr, xl
+}

+ 91 - 0
vendor/golang.org/x/crypto/blowfish/cipher.go

@@ -0,0 +1,91 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package blowfish implements Bruce Schneier's Blowfish encryption algorithm.
+package blowfish // import "golang.org/x/crypto/blowfish"
+
+// The code is a port of Bruce Schneier's C implementation.
+// See https://www.schneier.com/blowfish.html.
+
+import "strconv"
+
+// The Blowfish block size in bytes.
+const BlockSize = 8
+
+// A Cipher is an instance of Blowfish encryption using a particular key.
+type Cipher struct {
+	p              [18]uint32
+	s0, s1, s2, s3 [256]uint32
+}
+
+type KeySizeError int
+
+func (k KeySizeError) Error() string {
+	return "crypto/blowfish: invalid key size " + strconv.Itoa(int(k))
+}
+
+// NewCipher creates and returns a Cipher.
+// The key argument should be the Blowfish key, from 1 to 56 bytes.
+func NewCipher(key []byte) (*Cipher, error) {
+	var result Cipher
+	if k := len(key); k < 1 || k > 56 {
+		return nil, KeySizeError(k)
+	}
+	initCipher(&result)
+	ExpandKey(key, &result)
+	return &result, nil
+}
+
+// NewSaltedCipher creates a returns a Cipher that folds a salt into its key
+// schedule. For most purposes, NewCipher, instead of NewSaltedCipher, is
+// sufficient and desirable. For bcrypt compatibility, the key can be over 56
+// bytes.
+func NewSaltedCipher(key, salt []byte) (*Cipher, error) {
+	if len(salt) == 0 {
+		return NewCipher(key)
+	}
+	var result Cipher
+	if k := len(key); k < 1 {
+		return nil, KeySizeError(k)
+	}
+	initCipher(&result)
+	expandKeyWithSalt(key, salt, &result)
+	return &result, nil
+}
+
+// BlockSize returns the Blowfish block size, 8 bytes.
+// It is necessary to satisfy the Block interface in the
+// package "crypto/cipher".
+func (c *Cipher) BlockSize() int { return BlockSize }
+
+// Encrypt encrypts the 8-byte buffer src using the key k
+// and stores the result in dst.
+// Note that for amounts of data larger than a block,
+// it is not safe to just call Encrypt on successive blocks;
+// instead, use an encryption mode like CBC (see crypto/cipher/cbc.go).
+func (c *Cipher) Encrypt(dst, src []byte) {
+	l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
+	r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
+	l, r = encryptBlock(l, r, c)
+	dst[0], dst[1], dst[2], dst[3] = byte(l>>24), byte(l>>16), byte(l>>8), byte(l)
+	dst[4], dst[5], dst[6], dst[7] = byte(r>>24), byte(r>>16), byte(r>>8), byte(r)
+}
+
+// Decrypt decrypts the 8-byte buffer src using the key k
+// and stores the result in dst.
+func (c *Cipher) Decrypt(dst, src []byte) {
+	l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
+	r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
+	l, r = decryptBlock(l, r, c)
+	dst[0], dst[1], dst[2], dst[3] = byte(l>>24), byte(l>>16), byte(l>>8), byte(l)
+	dst[4], dst[5], dst[6], dst[7] = byte(r>>24), byte(r>>16), byte(r>>8), byte(r)
+}
+
+func initCipher(c *Cipher) {
+	copy(c.p[0:], p[0:])
+	copy(c.s0[0:], s0[0:])
+	copy(c.s1[0:], s1[0:])
+	copy(c.s2[0:], s2[0:])
+	copy(c.s3[0:], s3[0:])
+}

+ 199 - 0
vendor/golang.org/x/crypto/blowfish/const.go

@@ -0,0 +1,199 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The startup permutation array and substitution boxes.
+// They are the hexadecimal digits of PI; see:
+// https://www.schneier.com/code/constants.txt.
+
+package blowfish
+
+var s0 = [256]uint32{
+	0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96,
+	0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
+	0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658,
+	0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
+	0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e,
+	0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
+	0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6,
+	0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
+	0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c,
+	0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
+	0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1,
+	0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
+	0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a,
+	0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
+	0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176,
+	0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
+	0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706,
+	0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
+	0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b,
+	0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
+	0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c,
+	0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
+	0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a,
+	0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
+	0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760,
+	0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
+	0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8,
+	0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
+	0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33,
+	0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
+	0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0,
+	0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
+	0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777,
+	0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
+	0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705,
+	0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
+	0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e,
+	0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
+	0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9,
+	0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
+	0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f,
+	0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
+	0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a,
+}
+
+var s1 = [256]uint32{
+	0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d,
+	0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
+	0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65,
+	0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
+	0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9,
+	0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
+	0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d,
+	0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
+	0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc,
+	0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
+	0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908,
+	0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
+	0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124,
+	0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
+	0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908,
+	0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
+	0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b,
+	0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
+	0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa,
+	0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
+	0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d,
+	0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
+	0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5,
+	0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
+	0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96,
+	0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
+	0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca,
+	0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
+	0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77,
+	0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
+	0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054,
+	0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
+	0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea,
+	0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
+	0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646,
+	0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
+	0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea,
+	0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
+	0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e,
+	0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
+	0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd,
+	0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
+	0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7,
+}
+
+var s2 = [256]uint32{
+	0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7,
+	0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
+	0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af,
+	0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
+	0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4,
+	0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
+	0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec,
+	0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
+	0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332,
+	0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
+	0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58,
+	0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
+	0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22,
+	0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
+	0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60,
+	0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
+	0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99,
+	0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
+	0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74,
+	0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
+	0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3,
+	0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
+	0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979,
+	0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
+	0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa,
+	0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
+	0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086,
+	0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
+	0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24,
+	0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
+	0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84,
+	0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
+	0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09,
+	0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
+	0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe,
+	0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
+	0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0,
+	0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
+	0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188,
+	0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
+	0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8,
+	0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
+	0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0,
+}
+
+var s3 = [256]uint32{
+	0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742,
+	0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
+	0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79,
+	0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
+	0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a,
+	0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
+	0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1,
+	0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
+	0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797,
+	0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
+	0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6,
+	0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
+	0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba,
+	0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
+	0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5,
+	0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
+	0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce,
+	0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
+	0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd,
+	0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
+	0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb,
+	0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
+	0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc,
+	0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
+	0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc,
+	0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
+	0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a,
+	0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
+	0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a,
+	0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
+	0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b,
+	0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
+	0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e,
+	0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
+	0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623,
+	0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
+	0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a,
+	0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
+	0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3,
+	0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
+	0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c,
+	0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
+	0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6,
+}
+
+var p = [18]uint32{
+	0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0,
+	0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
+	0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b,
+}

+ 202 - 0
vendor/google.golang.org/appengine/LICENSE

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

+ 62 - 0
vendor/google.golang.org/appengine/cloudsql/cloudsql.go

@@ -0,0 +1,62 @@
+// Copyright 2013 Google Inc. All rights reserved.
+// Use of this source code is governed by the Apache 2.0
+// license that can be found in the LICENSE file.
+
+/*
+Package cloudsql exposes access to Google Cloud SQL databases.
+
+This package does not work in App Engine "flexible environment".
+
+This package is intended for MySQL drivers to make App Engine-specific
+connections. Applications should use this package through database/sql:
+Select a pure Go MySQL driver that supports this package, and use sql.Open
+with protocol "cloudsql" and an address of the Cloud SQL instance.
+
+A Go MySQL driver that has been tested to work well with Cloud SQL
+is the go-sql-driver:
+	import "database/sql"
+	import _ "github.com/go-sql-driver/mysql"
+
+	db, err := sql.Open("mysql", "user@cloudsql(project-id:instance-name)/dbname")
+
+
+Another driver that works well with Cloud SQL is the mymysql driver:
+	import "database/sql"
+	import _ "github.com/ziutek/mymysql/godrv"
+
+	db, err := sql.Open("mymysql", "cloudsql:instance-name*dbname/user/password")
+
+
+Using either of these drivers, you can perform a standard SQL query.
+This example assumes there is a table named 'users' with
+columns 'first_name' and 'last_name':
+
+	rows, err := db.Query("SELECT first_name, last_name FROM users")
+	if err != nil {
+		log.Errorf(ctx, "db.Query: %v", err)
+	}
+	defer rows.Close()
+
+	for rows.Next() {
+		var firstName string
+		var lastName string
+		if err := rows.Scan(&firstName, &lastName); err != nil {
+			log.Errorf(ctx, "rows.Scan: %v", err)
+			continue
+		}
+		log.Infof(ctx, "First: %v - Last: %v", firstName, lastName)
+	}
+	if err := rows.Err(); err != nil {
+		log.Errorf(ctx, "Row error: %v", err)
+	}
+*/
+package cloudsql
+
+import (
+	"net"
+)
+
+// Dial connects to the named Cloud SQL instance.
+func Dial(instance string) (net.Conn, error) {
+	return connect(instance)
+}

+ 17 - 0
vendor/google.golang.org/appengine/cloudsql/cloudsql_classic.go

@@ -0,0 +1,17 @@
+// Copyright 2013 Google Inc. All rights reserved.
+// Use of this source code is governed by the Apache 2.0
+// license that can be found in the LICENSE file.
+
+// +build appengine
+
+package cloudsql
+
+import (
+	"net"
+
+	"appengine/cloudsql"
+)
+
+func connect(instance string) (net.Conn, error) {
+	return cloudsql.Dial(instance)
+}

+ 16 - 0
vendor/google.golang.org/appengine/cloudsql/cloudsql_vm.go

@@ -0,0 +1,16 @@
+// Copyright 2013 Google Inc. All rights reserved.
+// Use of this source code is governed by the Apache 2.0
+// license that can be found in the LICENSE file.
+
+// +build !appengine
+
+package cloudsql
+
+import (
+	"errors"
+	"net"
+)
+
+func connect(instance string) (net.Conn, error) {
+	return nil, errors.New(`cloudsql: not supported in App Engine "flexible environment"`)
+}

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio