Pārlūkot izejas kodu

vendor: check in vendors

Bye bye glide...
Unknwon 8 gadi atpakaļ
vecāks
revīzija
2fd69f13d9
100 mainītis faili ar 14848 papildinājumiem un 225 dzēšanām
  1. 0 1
      .gitignore
  2. 4 0
      .gopmfile
  3. 2 11
      docker/build.sh
  4. 0 154
      glide.lock
  5. 0 59
      glide.yaml
  6. 8 0
      vendor/README
  7. 191 0
      vendor/github.com/Unknwon/cae/LICENSE
  8. 37 0
      vendor/github.com/Unknwon/cae/README.md
  9. 29 0
      vendor/github.com/Unknwon/cae/README_ZH.md
  10. 108 0
      vendor/github.com/Unknwon/cae/cae.go
  11. 67 0
      vendor/github.com/Unknwon/cae/zip/read.go
  12. 77 0
      vendor/github.com/Unknwon/cae/zip/stream.go
  13. 364 0
      vendor/github.com/Unknwon/cae/zip/write.go
  14. 238 0
      vendor/github.com/Unknwon/cae/zip/zip.go
  15. 191 0
      vendor/github.com/Unknwon/com/LICENSE
  16. 20 0
      vendor/github.com/Unknwon/com/README.md
  17. 161 0
      vendor/github.com/Unknwon/com/cmd.go
  18. 157 0
      vendor/github.com/Unknwon/com/convert.go
  19. 173 0
      vendor/github.com/Unknwon/com/dir.go
  20. 145 0
      vendor/github.com/Unknwon/com/file.go
  21. 60 0
      vendor/github.com/Unknwon/com/html.go
  22. 201 0
      vendor/github.com/Unknwon/com/http.go
  23. 29 0
      vendor/github.com/Unknwon/com/math.go
  24. 80 0
      vendor/github.com/Unknwon/com/path.go
  25. 56 0
      vendor/github.com/Unknwon/com/regex.go
  26. 87 0
      vendor/github.com/Unknwon/com/slice.go
  27. 243 0
      vendor/github.com/Unknwon/com/string.go
  28. 115 0
      vendor/github.com/Unknwon/com/time.go
  29. 41 0
      vendor/github.com/Unknwon/com/url.go
  30. 191 0
      vendor/github.com/Unknwon/i18n/LICENSE
  31. 134 0
      vendor/github.com/Unknwon/i18n/README.md
  32. 225 0
      vendor/github.com/Unknwon/i18n/i18n.go
  33. 202 0
      vendor/github.com/Unknwon/paginater/LICENSE
  34. 65 0
      vendor/github.com/Unknwon/paginater/README.md
  35. 197 0
      vendor/github.com/Unknwon/paginater/paginater.go
  36. 202 0
      vendor/github.com/bradfitz/gomemcache/LICENSE
  37. 666 0
      vendor/github.com/bradfitz/gomemcache/memcache/memcache.go
  38. 114 0
      vendor/github.com/bradfitz/gomemcache/memcache/selector.go
  39. 20 0
      vendor/github.com/fatih/color/LICENSE.md
  40. 175 0
      vendor/github.com/fatih/color/README.md
  41. 510 0
      vendor/github.com/fatih/color/color.go
  42. 128 0
      vendor/github.com/fatih/color/doc.go
  43. 191 0
      vendor/github.com/go-macaron/binding/LICENSE
  44. 20 0
      vendor/github.com/go-macaron/binding/README.md
  45. 669 0
      vendor/github.com/go-macaron/binding/binding.go
  46. 159 0
      vendor/github.com/go-macaron/binding/errors.go
  47. 191 0
      vendor/github.com/go-macaron/cache/LICENSE
  48. 20 0
      vendor/github.com/go-macaron/cache/README.md
  49. 122 0
      vendor/github.com/go-macaron/cache/cache.go
  50. 208 0
      vendor/github.com/go-macaron/cache/file.go
  51. 92 0
      vendor/github.com/go-macaron/cache/memcache/memcache.go
  52. 1 0
      vendor/github.com/go-macaron/cache/memcache/memcache.goconvey
  53. 179 0
      vendor/github.com/go-macaron/cache/memory.go
  54. 178 0
      vendor/github.com/go-macaron/cache/redis/redis.go
  55. 1 0
      vendor/github.com/go-macaron/cache/redis/redis.goconvey
  56. 84 0
      vendor/github.com/go-macaron/cache/utils.go
  57. 191 0
      vendor/github.com/go-macaron/captcha/LICENSE
  58. 16 0
      vendor/github.com/go-macaron/captcha/README.md
  59. 241 0
      vendor/github.com/go-macaron/captcha/captcha.go
  60. 498 0
      vendor/github.com/go-macaron/captcha/image.go
  61. 277 0
      vendor/github.com/go-macaron/captcha/siprng.go
  62. 191 0
      vendor/github.com/go-macaron/csrf/LICENSE
  63. 18 0
      vendor/github.com/go-macaron/csrf/README.md
  64. 251 0
      vendor/github.com/go-macaron/csrf/csrf.go
  65. 97 0
      vendor/github.com/go-macaron/csrf/xsrf.go
  66. 191 0
      vendor/github.com/go-macaron/gzip/LICENSE
  67. 20 0
      vendor/github.com/go-macaron/gzip/README.md
  68. 121 0
      vendor/github.com/go-macaron/gzip/gzip.go
  69. 191 0
      vendor/github.com/go-macaron/i18n/LICENSE
  70. 16 0
      vendor/github.com/go-macaron/i18n/README.md
  71. 225 0
      vendor/github.com/go-macaron/i18n/i18n.go
  72. 191 0
      vendor/github.com/go-macaron/inject/LICENSE
  73. 11 0
      vendor/github.com/go-macaron/inject/README.md
  74. 262 0
      vendor/github.com/go-macaron/inject/inject.go
  75. 191 0
      vendor/github.com/go-macaron/session/LICENSE
  76. 20 0
      vendor/github.com/go-macaron/session/README.md
  77. 261 0
      vendor/github.com/go-macaron/session/file.go
  78. 217 0
      vendor/github.com/go-macaron/session/memory.go
  79. 235 0
      vendor/github.com/go-macaron/session/redis/redis.go
  80. 1 0
      vendor/github.com/go-macaron/session/redis/redis.goconvey
  81. 399 0
      vendor/github.com/go-macaron/session/session.go
  82. 60 0
      vendor/github.com/go-macaron/session/utils.go
  83. 191 0
      vendor/github.com/go-macaron/toolbox/LICENSE
  84. 110 0
      vendor/github.com/go-macaron/toolbox/README.md
  85. 83 0
      vendor/github.com/go-macaron/toolbox/healthcheck.go
  86. 163 0
      vendor/github.com/go-macaron/toolbox/profile.go
  87. 138 0
      vendor/github.com/go-macaron/toolbox/statistic.go
  88. 154 0
      vendor/github.com/go-macaron/toolbox/toolbox.go
  89. 52 0
      vendor/github.com/go-sql-driver/mysql/AUTHORS
  90. 103 0
      vendor/github.com/go-sql-driver/mysql/CHANGELOG.md
  91. 23 0
      vendor/github.com/go-sql-driver/mysql/CONTRIBUTING.md
  92. 21 0
      vendor/github.com/go-sql-driver/mysql/ISSUE_TEMPLATE.md
  93. 373 0
      vendor/github.com/go-sql-driver/mysql/LICENSE
  94. 9 0
      vendor/github.com/go-sql-driver/mysql/PULL_REQUEST_TEMPLATE.md
  95. 420 0
      vendor/github.com/go-sql-driver/mysql/README.md
  96. 19 0
      vendor/github.com/go-sql-driver/mysql/appengine.go
  97. 147 0
      vendor/github.com/go-sql-driver/mysql/buffer.go
  98. 250 0
      vendor/github.com/go-sql-driver/mysql/collations.go
  99. 372 0
      vendor/github.com/go-sql-driver/mysql/connection.go
  100. 0 0
      vendor/github.com/go-sql-driver/mysql/const.go

+ 0 - 1
.gitignore

@@ -17,4 +17,3 @@ output*
 gogs.sublime-project
 gogs.sublime-workspace
 /release
-vendor

+ 4 - 0
.gopmfile

@@ -29,6 +29,8 @@ github.com/klauspost/compress = commit:461e8fd
 github.com/klauspost/cpuid = commit:09cded8
 github.com/klauspost/crc32 = commit:cb6bfca
 github.com/lib/pq = commit:67c3f2a
+github.com/mattn/go-colorable = commit:d228849
+github.com/mattn/go-isatty = commit:30a891c
 github.com/mattn/go-sqlite3 = commit:ce9149a
 github.com/mcuadros/go-version = commit:257f7b9
 github.com/microcosm-cc/bluemonday = commit:e797637
@@ -42,6 +44,7 @@ github.com/Unknwon/cae = commit:c6aac99
 github.com/Unknwon/com = commit:28b053d
 github.com/Unknwon/i18n = commit:39d6f27
 github.com/Unknwon/paginater = commit:701c23f
+github.com/fatih/color = commit:42c364b
 golang.org/x/crypto = commit:dc137be
 golang.org/x/net = commit:f249948
 golang.org/x/sys = commit:d75a526
@@ -49,6 +52,7 @@ golang.org/x/text = commit:ece019d
 gopkg.in/alexcesaro/quotedprintable.v3 = commit:2caba25
 gopkg.in/asn1-ber.v1 = commit:4e86f43
 gopkg.in/bufio.v1 = commit:567b2bf
+gopkg.in/clog.v1 = commit:d359c28
 gopkg.in/editorconfig/editorconfig-core-go.v1 = commit:a872f05
 gopkg.in/gomail.v2 = commit:81ebce5
 gopkg.in/ini.v1 = commit:e3c2d47

+ 2 - 11
docker/build.sh

@@ -10,23 +10,14 @@ export GO15VENDOREXPERIMENT=1
 # Install build deps
 apk --no-cache --no-progress add --virtual build-deps build-base linux-pam-dev go
 
-# Install glide
-git clone -b 0.10.2 https://github.com/Masterminds/glide ${GOPATH}/src/github.com/Masterminds/glide
-cd ${GOPATH}/src/github.com/Masterminds/glide
-make build
-go install
-
-
-
 # Build Gogs
 mkdir -p ${GOPATH}/src/github.com/gogits/
 ln -s /app/gogs/ ${GOPATH}/src/github.com/gogits/gogs
 cd ${GOPATH}/src/github.com/gogits/gogs
-glide install
 make build TAGS="sqlite cert pam"
 
-# Cleanup GOPATH & vendoring dir
-rm -r $GOPATH /app/gogs/vendor
+# Cleanup GOPATH
+rm -r $GOPATH
 
 # Remove build deps
 apk --no-progress del build-deps

+ 0 - 154
glide.lock

@@ -1,154 +0,0 @@
-hash: 1d5fcf2a90f7621ecbc0b1abed548e11d13bda3fea49b4326c829a523268e5cf
-updated: 2016-06-12T17:35:14.27036884+08:00
-imports:
-- name: github.com/bradfitz/gomemcache
-  version: 2fafb84a66c4911e11a8f50955b01e74fe3ab9c5
-  subpackages:
-  - memcache
-- name: github.com/urfave/cli
-  version: 347a9884a87374d000eec7e6445a34487c1f4a2b
-- name: github.com/go-macaron/binding
-  version: 48920167fa152d02f228cfbece7e0f1e452d200a
-- name: github.com/go-macaron/cache
-  version: 56173531277692bc2925924d51fda1cd0a6b8178
-  subpackages:
-  - memcache
-  - redis
-- name: github.com/go-macaron/captcha
-  version: 8aa5919789ab301e865595eb4b1114d6b9847deb
-- name: github.com/go-macaron/csrf
-  version: 6a9a7df172cc1fcd81e4585f44b09200b6087cc0
-- name: github.com/go-macaron/gzip
-  version: cad1c6580a07c56f5f6bc52d66002a05985c5854
-- name: github.com/go-macaron/i18n
-  version: ef57533c3b0fc2d8581deda14937e52f11a203ab
-- name: github.com/go-macaron/inject
-  version: d8a0b8677191f4380287cfebd08e462217bac7ad
-- name: github.com/go-macaron/session
-  version: 66031fcb37a0fff002a1f028eb0b3a815c78306b
-  subpackages:
-  - redis
-- name: github.com/go-macaron/toolbox
-  version: 82b511550b0aefc36b3a28062ad3a52e812bee38
-- name: github.com/go-sql-driver/mysql
-  version: 2e00b5cd70399450106cec6431c2e2ce3cae5034
-- name: github.com/go-xorm/builder
-  version: 867edcc549127f15667ece8876c3a60093c9634b
-- name: github.com/go-xorm/core
-  version: 2fbe2c76c6781d9e1c0398fc25386426e611f975
-- name: github.com/go-xorm/xorm
-  version: 445a934d32ed0934aedf0ef99b4b7c69b22f8e58
-- name: github.com/gogits/chardet
-  version: 2404f777256163ea3eadb273dada5dcb037993c0
-- name: github.com/gogits/cron
-  version: 2fc07a4c4f1e3c4d2301c5ed578d5e2c31c70421
-- name: github.com/gogits/git-module
-  version: 172cbc21accbf0085a58fd0832f46a9f694130e8
-- name: github.com/gogits/go-gogs-client
-  version: 98046bb98061fc6baa5bb86359af0b7c300d384a
-- name: github.com/gogits/go-libravatar
-  version: cd1abbd55d09b793672732a7a1dfdaa12a40dfd0
-- name: github.com/issue9/identicon
-  version: d36b54562f4cf70c83653e13dc95c220c79ef521
-- name: github.com/jaytaylor/html2text
-  version: d16d4129aab4e6be4497f4db898965f09b93b565
-- name: github.com/kardianos/minwinsvc
-  version: cad6b2b879b0970e4245a20ebf1a81a756e2bb70
-- name: github.com/klauspost/compress
-  version: 461e8fd8397ae84a23f56e385801e4feda2048ce
-  subpackages:
-  - gzip
-  - flate
-- name: github.com/klauspost/cpuid
-  version: 09cded8978dc9e80714c4d85b0322337b0a1e5e0
-- name: github.com/klauspost/crc32
-  version: cb6bfca970f6908083f26f39a79009d608efd5cd
-- name: github.com/lib/pq
-  version: 67c3f2a8884c9b1aac5503c8d42ae4f73a93511c
-  subpackages:
-  - oid
-- name: github.com/mattn/go-sqlite3
-  version: ce9149a3c941c30de51a01dbc5bc414ddaa52927
-- name: github.com/mcuadros/go-version
-  version: 257f7b9a7d87427c8d7f89469a5958d57f8abd7c
-- name: github.com/microcosm-cc/bluemonday
-  version: e79763773ab6222ca1d5a7cbd9d62d83c1f77081
-- name: github.com/msteinert/pam
-  version: 02ccfbfaf0cc627aa3aec8ef7ed5cfeec5b43f63
-- name: github.com/nfnt/resize
-  version: 891127d8d1b52734debe1b3c3d7e747502b6c366
-- name: github.com/russross/blackfriday
-  version: 5f33e7b7878355cd2b7e6b8eefc48a5472c69f70
-- name: github.com/satori/go.uuid
-  version: b061729afc07e77a8aa4fad0a2fd840958f1942a
-- name: github.com/sergi/go-diff
-  version: 24e2351369ec4949b2ed0dc5c477afdd4c4034e8
-  subpackages:
-  - diffmatchpatch
-- name: github.com/shurcooL/sanitized_anchor_name
-  version: 1dba4b3954bc059efc3991ec364f9f9a35f597d2
-- name: github.com/Unknwon/cae
-  version: c6aac99ea2cae2ebaf23f26f76b04fe3fcfc9f8c
-  subpackages:
-  - zip
-- name: github.com/Unknwon/com
-  version: 28b053d5a2923b87ce8c5a08f3af779894a72758
-- name: github.com/Unknwon/i18n
-  version: 39d6f2727e0698b1021ceb6a77c1801aa92e7d5d
-- name: github.com/Unknwon/paginater
-  version: 701c23f468663c34d1b1768c3ae1bcc57e11c5b3
-- name: golang.org/x/crypto
-  version: dc137beb6cce2043eb6b5f223ab8bf51c32459f4
-  subpackages:
-  - ssh
-  - curve25519
-  - ed25519
-  - ed25519/internal/edwards25519
-- name: golang.org/x/net
-  version: f2499483f923065a842d38eb4c7f1927e6fc6e6d
-  subpackages:
-  - html
-  - html/charset
-  - html/atom
-- name: golang.org/x/sys
-  version: d75a52659825e75fff6158388dddc6a5b04f9ba5
-  subpackages:
-  - windows/svc
-  - windows
-- name: golang.org/x/text
-  version: ece019dcfd29abcf65d0d1dfe145e8faad097640
-  subpackages:
-  - transform
-  - language
-  - encoding
-  - encoding/charmap
-  - encoding/htmlindex
-  - internal/tag
-  - encoding/internal/identifier
-  - encoding/internal
-  - encoding/japanese
-  - encoding/korean
-  - encoding/simplifiedchinese
-  - encoding/traditionalchinese
-  - encoding/unicode
-  - internal/utf8internal
-  - runes
-- name: gopkg.in/alexcesaro/quotedprintable.v3
-  version: 2caba252f4dc53eaf6b553000885530023f54623
-- name: gopkg.in/asn1-ber.v1
-  version: 4e86f4367175e39f69d9358a5f17b4dda270378d
-- name: gopkg.in/bufio.v1
-  version: 567b2bfa514e796916c4747494d6ff5132a1dfce
-- name: gopkg.in/editorconfig/editorconfig-core-go.v1
-  version: a872f05c2e34b37b567401384d202aff11ba06d4
-- name: gopkg.in/gomail.v2
-  version: 81ebce5c23dfd25c6c67194b37d3dd3f338c98b1
-- name: gopkg.in/ini.v1
-  version: e3c2d47c61e5333f9aa2974695dd94396eb69c75
-- name: gopkg.in/ldap.v2
-  version: 8168ee085ee43257585e50c6441aadf54ecb2c9f
-- name: gopkg.in/macaron.v1
-  version: 78521e4647ad5dcbabd5734d94582ca2373cbad8
-- name: gopkg.in/redis.v2
-  version: e6179049628164864e6e84e973cfb56335748dea
-devImports: []

+ 0 - 59
glide.yaml

@@ -1,59 +0,0 @@
-package: github.com/gogits/gogs
-import:
-- package: github.com/Unknwon/cae
-  subpackages:
-  - zip
-- package: github.com/Unknwon/com
-- package: github.com/Unknwon/i18n
-- package: github.com/Unknwon/paginater
-- package: github.com/urfave/cli
-- package: github.com/go-macaron/binding
-- package: github.com/go-macaron/cache
-  subpackages:
-  - memcache
-  - redis
-- package: github.com/go-macaron/captcha
-- package: github.com/go-macaron/csrf
-- package: github.com/go-macaron/gzip
-- package: github.com/go-macaron/i18n
-- package: github.com/go-macaron/session
-  subpackages:
-  - redis
-- package: github.com/go-macaron/toolbox
-- package: github.com/go-sql-driver/mysql
-- package: github.com/go-xorm/core
-- package: github.com/go-xorm/xorm
-- package: github.com/gogits/chardet
-- package: github.com/gogits/cron
-- package: github.com/gogits/git-module
-- package: github.com/gogits/go-gogs-client
-- package: github.com/issue9/identicon
-- package: github.com/kardianos/minwinsvc
-- package: github.com/lib/pq
-- package: github.com/mattn/go-sqlite3
-- package: github.com/mcuadros/go-version
-- package: github.com/microcosm-cc/bluemonday
-- package: github.com/msteinert/pam
-- package: github.com/nfnt/resize
-- package: github.com/russross/blackfriday
-- package: github.com/satori/go.uuid
-- package: github.com/sergi/go-diff
-  subpackages:
-  - diffmatchpatch
-- package: github.com/strk/go-libravatar
-- package: golang.org/x/crypto
-  subpackages:
-  - ssh
-- package: golang.org/x/net
-  subpackages:
-  - html
-  - html/charset
-- package: golang.org/x/text
-  subpackages:
-  - transform
-  - language
-- package: gopkg.in/editorconfig/editorconfig-core-go.v1
-- package: gopkg.in/gomail.v2
-- package: gopkg.in/ini.v1
-- package: gopkg.in/ldap.v2
-- package: gopkg.in/macaron.v1

+ 8 - 0
vendor/README

@@ -0,0 +1,8 @@
+1. Delete package directory from vendor when developing new code of dependency.
+2. After commit on dependency, run:
+	govendor update <import path>
+3. Introduce a new dependency, run:
+	govendor add +vendor <import path>
+4. To update all deependencies, delete all packages from vendor, and run:
+	govendor add +vendor +external
+5. Too hard.

+ 191 - 0
vendor/github.com/Unknwon/cae/LICENSE

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

+ 37 - 0
vendor/github.com/Unknwon/cae/README.md

@@ -0,0 +1,37 @@
+Compression and Archive Extensions
+==================================
+
+[![Go Walker](http://gowalker.org/api/v1/badge)](http://gowalker.org/github.com/Unknwon/cae)
+
+[中文文档](README_ZH.md)
+
+Package cae implements PHP-like Compression and Archive Extensions.
+
+But this package has some modifications depends on Go-style.
+
+Reference: [PHP:Compression and Archive Extensions](http://www.php.net/manual/en/refs.compression.php).
+
+Code Convention: based on [Go Code Convention](https://github.com/Unknwon/go-code-convention).
+
+### Implementations
+
+Package `zip`([Go Walker](http://gowalker.org/github.com/Unknwon/cae/zip)) and `tz`([Go Walker](http://gowalker.org/github.com/Unknwon/cae/tz)) both enable you to transparently read or write ZIP/TAR.GZ compressed archives and the files inside them.
+
+- Features:
+	- Add file or directory from everywhere to archive, no one-to-one limitation.
+	- Extract part of entries, not all at once. 
+	- Stream data directly into `io.Writer` without any file system storage.
+
+### Test cases and Coverage
+
+All subpackages use [GoConvey](http://goconvey.co/) to write test cases, and coverage is more than 80 percent.
+
+### Use cases
+
+- [Gogs](https://github.com/gogits/gogs): self hosted Git service in the Go Programming Language.
+- [GoBlog](https://github.com/fuxiaohei/GoBlog): personal blogging application.
+- [GoBuild](https://github.com/shxsun/gobuild/): online Go cross-platform compilation and download service.
+
+## License
+
+This project is under Apache v2 License. See the [LICENSE](LICENSE) file for the full license text.

+ 29 - 0
vendor/github.com/Unknwon/cae/README_ZH.md

@@ -0,0 +1,29 @@
+压缩与打包扩展
+=============
+
+[![Go Walker](http://gowalker.org/api/v1/badge)](http://gowalker.org/github.com/Unknwon/cae)
+
+包 cae 实现了 PHP 风格的压缩与打包扩展。
+
+但本包依据 Go 语言的风格进行了一些修改。
+
+引用:[PHP:Compression and Archive Extensions](http://www.php.net/manual/en/refs.compression.php)
+
+编码规范:基于 [Go 编码规范](https://github.com/Unknwon/go-code-convention)
+
+### 实现
+
+包 `zip`([Go Walker](http://gowalker.org/github.com/Unknwon/cae/zip)) 和 `tz`([Go Walker](http://gowalker.org/github.com/Unknwon/cae/tz)) 都允许你轻易的读取或写入 ZIP/TAR.GZ 压缩档案和其内部文件。
+
+- 特性:
+	- 将任意位置的文件或目录加入档案,没有一对一的操作限制。
+	- 只解压部分文件,而非一次性解压全部。 
+	- 将数据以流的形式直接写入 `io.Writer` 而不需经过文件系统的存储。
+
+### 测试用例与覆盖率
+
+所有子包均采用 [GoConvey](http://goconvey.co/) 来书写测试用例,覆盖率均超过 80%。
+
+## 授权许可
+
+本项目采用 Apache v2 开源授权许可证,完整的授权说明已放置在 [LICENSE](LICENSE) 文件中。

+ 108 - 0
vendor/github.com/Unknwon/cae/cae.go

@@ -0,0 +1,108 @@
+// Copyright 2013 Unknown
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+// Package cae implements PHP-like Compression and Archive Extensions.
+package cae
+
+import (
+	"io"
+	"os"
+	"strings"
+)
+
+// A Streamer describes an streamable archive object.
+type Streamer interface {
+	StreamFile(string, os.FileInfo, []byte) error
+	StreamReader(string, os.FileInfo, io.Reader) error
+	Close() error
+}
+
+// A HookFunc represents a middleware for packing and extracting archive.
+type HookFunc func(string, os.FileInfo) error
+
+// HasPrefix returns true if name has any string in given slice as prefix.
+func HasPrefix(name string, prefixes []string) bool {
+	for _, prefix := range prefixes {
+		if strings.HasPrefix(name, prefix) {
+			return true
+		}
+	}
+	return false
+}
+
+// IsEntry returns true if name equals to any string in given slice.
+func IsEntry(name string, entries []string) bool {
+	for _, e := range entries {
+		if e == name {
+			return true
+		}
+	}
+	return false
+}
+
+// IsFilter returns true if given name matches any of global filter rule.
+func IsFilter(name string) bool {
+	if strings.Contains(name, ".DS_Store") {
+		return true
+	}
+	return false
+}
+
+// IsExist returns true if given path is a file or directory.
+func IsExist(path string) bool {
+	_, err := os.Stat(path)
+	return err == nil || os.IsExist(err)
+}
+
+// Copy copies file from source to target path.
+func Copy(dest, src string) error {
+	// Gather file information to set back later.
+	si, err := os.Lstat(src)
+	if err != nil {
+		return err
+	}
+
+	// Handle symbolic link.
+	if si.Mode()&os.ModeSymlink != 0 {
+		target, err := os.Readlink(src)
+		if err != nil {
+			return err
+		}
+		// NOTE: os.Chmod and os.Chtimes don't recoganize symbolic link,
+		// which will lead "no such file or directory" error.
+		return os.Symlink(target, dest)
+	}
+
+	sr, err := os.Open(src)
+	if err != nil {
+		return err
+	}
+	defer sr.Close()
+
+	dw, err := os.Create(dest)
+	if err != nil {
+		return err
+	}
+	defer dw.Close()
+
+	if _, err = io.Copy(dw, sr); err != nil {
+		return err
+	}
+
+	// Set back file information.
+	if err = os.Chtimes(dest, si.ModTime(), si.ModTime()); err != nil {
+		return err
+	}
+	return os.Chmod(dest, si.Mode())
+}

+ 67 - 0
vendor/github.com/Unknwon/cae/zip/read.go

@@ -0,0 +1,67 @@
+// Copyright 2013 Unknown
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package zip
+
+import (
+	"archive/zip"
+	"os"
+	"strings"
+)
+
+// OpenFile is the generalized open call; most users will use Open
+// instead. It opens the named zip file with specified flag
+// (O_RDONLY etc.) if applicable. If successful,
+// methods on the returned ZipArchive can be used for I/O.
+// If there is an error, it will be of type *PathError.
+func (z *ZipArchive) Open(name string, flag int, perm os.FileMode) error {
+	// Create a new archive if it's specified and not exist.
+	if flag&os.O_CREATE != 0 {
+		f, err := os.Create(name)
+		if err != nil {
+			return err
+		}
+		zw := zip.NewWriter(f)
+		if err = zw.Close(); err != nil {
+			return err
+		}
+	}
+
+	rc, err := zip.OpenReader(name)
+	if err != nil {
+		return err
+	}
+
+	z.ReadCloser = rc
+	z.FileName = name
+	z.Comment = rc.Comment
+	z.NumFiles = len(rc.File)
+	z.Flag = flag
+	z.Permission = perm
+	z.isHasChanged = false
+
+	z.files = make([]*File, z.NumFiles)
+	for i, f := range rc.File {
+		z.files[i] = &File{}
+		z.files[i].FileHeader, err = zip.FileInfoHeader(f.FileInfo())
+		if err != nil {
+			return err
+		}
+		z.files[i].Name = strings.Replace(f.Name, "\\", "/", -1)
+		if f.FileInfo().IsDir() && !strings.HasSuffix(z.files[i].Name, "/") {
+			z.files[i].Name += "/"
+		}
+	}
+	return nil
+}

+ 77 - 0
vendor/github.com/Unknwon/cae/zip/stream.go

@@ -0,0 +1,77 @@
+// Copyright 2014 Unknown
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package zip
+
+import (
+	"archive/zip"
+	"io"
+	"os"
+	"path/filepath"
+)
+
+// A StreamArchive represents a streamable archive.
+type StreamArchive struct {
+	*zip.Writer
+}
+
+// NewStreamArachive returns a new streamable archive with given io.Writer.
+// It's caller's responsibility to close io.Writer and streamer after operation.
+func NewStreamArachive(w io.Writer) *StreamArchive {
+	return &StreamArchive{zip.NewWriter(w)}
+}
+
+// StreamFile streams a file or directory entry into StreamArchive.
+func (s *StreamArchive) StreamFile(relPath string, fi os.FileInfo, data []byte) error {
+	if fi.IsDir() {
+		fh, err := zip.FileInfoHeader(fi)
+		if err != nil {
+			return err
+		}
+		fh.Name = relPath + "/"
+		if _, err = s.Writer.CreateHeader(fh); err != nil {
+			return err
+		}
+	} else {
+		fh, err := zip.FileInfoHeader(fi)
+		if err != nil {
+			return err
+		}
+		fh.Name = filepath.Join(relPath, fi.Name())
+		fh.Method = zip.Deflate
+		fw, err := s.Writer.CreateHeader(fh)
+		if err != nil {
+			return err
+		} else if _, err = fw.Write(data); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// StreamReader streams data from io.Reader to StreamArchive.
+func (s *StreamArchive) StreamReader(relPath string, fi os.FileInfo, r io.Reader) (err error) {
+	fh, err := zip.FileInfoHeader(fi)
+	if err != nil {
+		return err
+	}
+	fh.Name = filepath.Join(relPath, fi.Name())
+
+	fw, err := s.Writer.CreateHeader(fh)
+	if err != nil {
+		return err
+	}
+	_, err = io.Copy(fw, r)
+	return err
+}

+ 364 - 0
vendor/github.com/Unknwon/cae/zip/write.go

@@ -0,0 +1,364 @@
+// Copyright 2013 Unknown
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package zip
+
+import (
+	"archive/zip"
+	"fmt"
+	"io"
+	"os"
+	"path"
+	"path/filepath"
+	"strings"
+
+	"github.com/Unknwon/cae"
+)
+
+// Switcher of printing trace information when pack and extract.
+var Verbose = true
+
+// extractFile extracts zip.File to file system.
+func extractFile(f *zip.File, destPath string) error {
+	filePath := path.Join(destPath, f.Name)
+	os.MkdirAll(path.Dir(filePath), os.ModePerm)
+
+	rc, err := f.Open()
+	if err != nil {
+		return err
+	}
+	defer rc.Close()
+
+	fw, err := os.Create(filePath)
+	if err != nil {
+		return err
+	}
+	defer fw.Close()
+
+	if _, err = io.Copy(fw, rc); err != nil {
+		return err
+	}
+
+	// Skip symbolic links.
+	if f.FileInfo().Mode()&os.ModeSymlink != 0 {
+		return nil
+	}
+	// Set back file information.
+	if err = os.Chtimes(filePath, f.ModTime(), f.ModTime()); err != nil {
+		return err
+	}
+	return os.Chmod(filePath, f.FileInfo().Mode())
+}
+
+var defaultExtractFunc = func(fullName string, fi os.FileInfo) error {
+	if !Verbose {
+		return nil
+	}
+
+	fmt.Println("Extracting file..." + fullName)
+	return nil
+}
+
+// ExtractToFunc extracts the whole archive or the given files to the
+// specified destination.
+// It accepts a function as a middleware for custom operations.
+func (z *ZipArchive) ExtractToFunc(destPath string, fn cae.HookFunc, entries ...string) (err error) {
+	destPath = strings.Replace(destPath, "\\", "/", -1)
+	isHasEntry := len(entries) > 0
+	if Verbose {
+		fmt.Println("Unzipping " + z.FileName + "...")
+	}
+	os.MkdirAll(destPath, os.ModePerm)
+	for _, f := range z.File {
+		f.Name = strings.Replace(f.Name, "\\", "/", -1)
+
+		// Directory.
+		if strings.HasSuffix(f.Name, "/") {
+			if isHasEntry {
+				if cae.IsEntry(f.Name, entries) {
+					if err = fn(f.Name, f.FileInfo()); err != nil {
+						continue
+					}
+					os.MkdirAll(path.Join(destPath, f.Name), os.ModePerm)
+				}
+				continue
+			}
+			if err = fn(f.Name, f.FileInfo()); err != nil {
+				continue
+			}
+			os.MkdirAll(path.Join(destPath, f.Name), os.ModePerm)
+			continue
+		}
+
+		// File.
+		if isHasEntry {
+			if cae.IsEntry(f.Name, entries) {
+				if err = fn(f.Name, f.FileInfo()); err != nil {
+					continue
+				}
+				err = extractFile(f, destPath)
+			}
+		} else {
+			if err = fn(f.Name, f.FileInfo()); err != nil {
+				continue
+			}
+			err = extractFile(f, destPath)
+		}
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// ExtractToFunc extracts the whole archive or the given files to the
+// specified destination.
+// It accepts a function as a middleware for custom operations.
+func ExtractToFunc(srcPath, destPath string, fn cae.HookFunc, entries ...string) (err error) {
+	z, err := Open(srcPath)
+	if err != nil {
+		return err
+	}
+	defer z.Close()
+	return z.ExtractToFunc(destPath, fn, entries...)
+}
+
+// ExtractTo extracts the whole archive or the given files to the
+// specified destination.
+// Call Flush() to apply changes before this.
+func (z *ZipArchive) ExtractTo(destPath string, entries ...string) (err error) {
+	return z.ExtractToFunc(destPath, defaultExtractFunc, entries...)
+}
+
+// ExtractTo extracts given archive or the given files to the
+// specified destination.
+func ExtractTo(srcPath, destPath string, entries ...string) (err error) {
+	return ExtractToFunc(srcPath, destPath, defaultExtractFunc, entries...)
+}
+
+// extractFile extracts file from ZipArchive to file system.
+func (z *ZipArchive) extractFile(f *File) error {
+	if !z.isHasWriter {
+		for _, zf := range z.ReadCloser.File {
+			if f.Name == zf.Name {
+				return extractFile(zf, path.Dir(f.tmpPath))
+			}
+		}
+	}
+	return cae.Copy(f.tmpPath, f.absPath)
+}
+
+// Flush saves changes to original zip file if any.
+func (z *ZipArchive) Flush() error {
+	if !z.isHasChanged || (z.ReadCloser == nil && !z.isHasWriter) {
+		return nil
+	}
+
+	// Extract to tmp path and pack back.
+	tmpPath := path.Join(os.TempDir(), "cae", path.Base(z.FileName))
+	os.RemoveAll(tmpPath)
+	defer os.RemoveAll(tmpPath)
+
+	for _, f := range z.files {
+		if strings.HasSuffix(f.Name, "/") {
+			os.MkdirAll(path.Join(tmpPath, f.Name), os.ModePerm)
+			continue
+		}
+
+		// Relative path inside zip temporary changed.
+		f.tmpPath = path.Join(tmpPath, f.Name)
+		if err := z.extractFile(f); err != nil {
+			return err
+		}
+	}
+
+	if z.isHasWriter {
+		return packToWriter(tmpPath, z.writer, defaultPackFunc, true)
+	}
+
+	if err := PackTo(tmpPath, z.FileName); err != nil {
+		return err
+	}
+	return z.Open(z.FileName, os.O_RDWR|os.O_TRUNC, z.Permission)
+}
+
+// packFile packs a file or directory to zip.Writer.
+func packFile(srcFile string, recPath string, zw *zip.Writer, fi os.FileInfo) error {
+	if fi.IsDir() {
+		fh, err := zip.FileInfoHeader(fi)
+		if err != nil {
+			return err
+		}
+		fh.Name = recPath + "/"
+		if _, err = zw.CreateHeader(fh); err != nil {
+			return err
+		}
+	} else {
+		fh, err := zip.FileInfoHeader(fi)
+		if err != nil {
+			return err
+		}
+		fh.Name = recPath
+		fh.Method = zip.Deflate
+
+		fw, err := zw.CreateHeader(fh)
+		if err != nil {
+			return err
+		}
+
+		if fi.Mode()&os.ModeSymlink != 0 {
+			target, err := os.Readlink(srcFile)
+			if err != nil {
+				return err
+			}
+			if _, err = fw.Write([]byte(target)); err != nil {
+				return err
+			}
+		} else {
+			f, err := os.Open(srcFile)
+			if err != nil {
+				return err
+			}
+			defer f.Close()
+			
+			if _, err = io.Copy(fw, f); err != nil {
+				return err
+			}
+		}
+	}
+	return nil
+}
+
+// packDir packs a directory and its subdirectories and files
+// recursively to zip.Writer.
+func packDir(srcPath string, recPath string, zw *zip.Writer, fn cae.HookFunc) error {
+	dir, err := os.Open(srcPath)
+	if err != nil {
+		return err
+	}
+	defer dir.Close()
+
+	fis, err := dir.Readdir(0)
+	if err != nil {
+		return err
+	}
+	for _, fi := range fis {
+		if cae.IsFilter(fi.Name()) {
+			continue
+		}
+		curPath := srcPath + "/" + fi.Name()
+		tmpRecPath := filepath.Join(recPath, fi.Name())
+		if err = fn(curPath, fi); err != nil {
+			continue
+		}
+
+		if fi.IsDir() {
+			if err = packFile(srcPath, tmpRecPath, zw, fi); err != nil {
+				return err
+			}
+			err = packDir(curPath, tmpRecPath, zw, fn)
+		} else {
+			err = packFile(curPath, tmpRecPath, zw, fi)
+		}
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// packToWriter packs given path object to io.Writer.
+func packToWriter(srcPath string, w io.Writer, fn func(fullName string, fi os.FileInfo) error, includeDir bool) error {
+	zw := zip.NewWriter(w)
+	defer zw.Close()
+
+	f, err := os.Open(srcPath)
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+
+	fi, err := f.Stat()
+	if err != nil {
+		return err
+	}
+
+	basePath := path.Base(srcPath)
+	if fi.IsDir() {
+		if includeDir {
+			if err = packFile(srcPath, basePath, zw, fi); err != nil {
+				return err
+			}
+		} else {
+			basePath = ""
+		}
+		return packDir(srcPath, basePath, zw, fn)
+	}
+	return packFile(srcPath, basePath, zw, fi)
+}
+
+// packTo packs given source path object to target path.
+func packTo(srcPath, destPath string, fn cae.HookFunc, includeDir bool) error {
+	fw, err := os.Create(destPath)
+	if err != nil {
+		return err
+	}
+	defer fw.Close()
+
+	return packToWriter(srcPath, fw, fn, includeDir)
+}
+
+// PackToFunc packs the complete archive to the specified destination.
+// It accepts a function as a middleware for custom operations.
+func PackToFunc(srcPath, destPath string, fn func(fullName string, fi os.FileInfo) error, includeDir ...bool) error {
+	isIncludeDir := false
+	if len(includeDir) > 0 && includeDir[0] {
+		isIncludeDir = true
+	}
+	return packTo(srcPath, destPath, fn, isIncludeDir)
+}
+
+var defaultPackFunc = func(fullName string, fi os.FileInfo) error {
+	if !Verbose {
+		return nil
+	}
+
+	if fi.IsDir() {
+		fmt.Printf("Adding dir...%s\n", fullName)
+	} else {
+		fmt.Printf("Adding file...%s\n", fullName)
+	}
+	return nil
+}
+
+// PackTo packs the whole archive to the specified destination.
+// Call Flush() will automatically call this in the end.
+func PackTo(srcPath, destPath string, includeDir ...bool) error {
+	return PackToFunc(srcPath, destPath, defaultPackFunc, includeDir...)
+}
+
+// Close opens or creates archive and save changes.
+func (z *ZipArchive) Close() (err error) {
+	if err = z.Flush(); err != nil {
+		return err
+	}
+
+	if z.ReadCloser != nil {
+		if err = z.ReadCloser.Close(); err != nil {
+			return err
+		}
+		z.ReadCloser = nil
+	}
+	return nil
+}

+ 238 - 0
vendor/github.com/Unknwon/cae/zip/zip.go

@@ -0,0 +1,238 @@
+// Copyright 2013 Unknown
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+// Package zip enables you to transparently read or write ZIP compressed archives and the files inside them.
+package zip
+
+import (
+	"archive/zip"
+	"errors"
+	"io"
+	"os"
+	"path"
+	"strings"
+
+	"github.com/Unknwon/cae"
+)
+
+// A File represents a file or directory entry in archive.
+type File struct {
+	*zip.FileHeader
+	oldName    string // NOTE: unused, for future change name feature.
+	oldComment string // NOTE: unused, for future change comment feature.
+	absPath    string // Absolute path of local file system.
+	tmpPath    string
+}
+
+// A ZipArchive represents a file archive, compressed with Zip.
+type ZipArchive struct {
+	*zip.ReadCloser
+	FileName   string
+	Comment    string
+	NumFiles   int
+	Flag       int
+	Permission os.FileMode
+
+	files        []*File
+	isHasChanged bool
+
+	// For supporting flushing to io.Writer.
+	writer      io.Writer
+	isHasWriter bool
+}
+
+// OpenFile is the generalized open call; most users will use Open
+// instead. It opens the named zip file with specified flag
+// (O_RDONLY etc.) if applicable. If successful,
+// methods on the returned ZipArchive can be used for I/O.
+// If there is an error, it will be of type *PathError.
+func OpenFile(name string, flag int, perm os.FileMode) (*ZipArchive, error) {
+	z := new(ZipArchive)
+	err := z.Open(name, flag, perm)
+	return z, err
+}
+
+// Create creates the named zip file, truncating
+// it if it already exists. If successful, methods on the returned
+// ZipArchive can be used for I/O; the associated file descriptor has mode
+// O_RDWR.
+// If there is an error, it will be of type *PathError.
+func Create(name string) (*ZipArchive, error) {
+	os.MkdirAll(path.Dir(name), os.ModePerm)
+	return OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
+}
+
+// Open opens the named zip file for reading. If successful, methods on
+// the returned ZipArchive can be used for reading; the associated file
+// descriptor has mode O_RDONLY.
+// If there is an error, it will be of type *PathError.
+func Open(name string) (*ZipArchive, error) {
+	return OpenFile(name, os.O_RDONLY, 0)
+}
+
+// New accepts a variable that implemented interface io.Writer
+// for write-only purpose operations.
+func New(w io.Writer) *ZipArchive {
+	return &ZipArchive{
+		writer:      w,
+		isHasWriter: true,
+	}
+}
+
+// List returns a string slice of files' name in ZipArchive.
+// Specify prefixes will be used as filters.
+func (z *ZipArchive) List(prefixes ...string) []string {
+	isHasPrefix := len(prefixes) > 0
+	names := make([]string, 0, z.NumFiles)
+	for _, f := range z.files {
+		if isHasPrefix && !cae.HasPrefix(f.Name, prefixes) {
+			continue
+		}
+		names = append(names, f.Name)
+	}
+	return names
+}
+
+// AddEmptyDir adds a raw directory entry to ZipArchive,
+// it returns false if same directory enry already existed.
+func (z *ZipArchive) AddEmptyDir(dirPath string) bool {
+	dirPath = strings.Replace(dirPath, "\\", "/", -1)
+
+	if !strings.HasSuffix(dirPath, "/") {
+		dirPath += "/"
+	}
+
+	for _, f := range z.files {
+		if dirPath == f.Name {
+			return false
+		}
+	}
+
+	dirPath = strings.TrimSuffix(dirPath, "/")
+	if strings.Contains(dirPath, "/") {
+		// Auto add all upper level directories.
+		z.AddEmptyDir(path.Dir(dirPath))
+	}
+	z.files = append(z.files, &File{
+		FileHeader: &zip.FileHeader{
+			Name:             dirPath + "/",
+			UncompressedSize: 0,
+		},
+	})
+	z.updateStat()
+	return true
+}
+
+// AddDir adds a directory and subdirectories entries to ZipArchive.
+func (z *ZipArchive) AddDir(dirPath, absPath string) error {
+	dir, err := os.Open(absPath)
+	if err != nil {
+		return err
+	}
+	defer dir.Close()
+
+	// Make sure we have all upper level directories.
+	z.AddEmptyDir(dirPath)
+
+	fis, err := dir.Readdir(0)
+	if err != nil {
+		return err
+	}
+	for _, fi := range fis {
+		curPath := absPath + "/" + fi.Name()
+		tmpRecPath := path.Join(dirPath, fi.Name())
+		if fi.IsDir() {
+			if err = z.AddDir(tmpRecPath, curPath); err != nil {
+				return err
+			}
+		} else {
+			if err = z.AddFile(tmpRecPath, curPath); err != nil {
+				return err
+			}
+		}
+	}
+	return nil
+}
+
+// updateStat should be called after every change for rebuilding statistic.
+func (z *ZipArchive) updateStat() {
+	z.NumFiles = len(z.files)
+	z.isHasChanged = true
+}
+
+// AddFile adds a file entry to ZipArchive.
+func (z *ZipArchive) AddFile(fileName, absPath string) error {
+	fileName = strings.Replace(fileName, "\\", "/", -1)
+	absPath = strings.Replace(absPath, "\\", "/", -1)
+
+	if cae.IsFilter(absPath) {
+		return nil
+	}
+
+	f, err := os.Open(absPath)
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+
+	fi, err := f.Stat()
+	if err != nil {
+		return err
+	}
+
+	file := new(File)
+	file.FileHeader, err = zip.FileInfoHeader(fi)
+	if err != nil {
+		return err
+	}
+	file.Name = fileName
+	file.absPath = absPath
+
+	z.AddEmptyDir(path.Dir(fileName))
+
+	isExist := false
+	for _, f := range z.files {
+		if fileName == f.Name {
+			f = file
+			isExist = true
+			break
+		}
+	}
+	if !isExist {
+		z.files = append(z.files, file)
+	}
+
+	z.updateStat()
+	return nil
+}
+
+// DeleteIndex deletes an entry in the archive by its index.
+func (z *ZipArchive) DeleteIndex(idx int) error {
+	if idx >= z.NumFiles {
+		return errors.New("index out of range of number of files")
+	}
+
+	z.files = append(z.files[:idx], z.files[idx+1:]...)
+	return nil
+}
+
+// DeleteName deletes an entry in the archive by its name.
+func (z *ZipArchive) DeleteName(name string) error {
+	for i, f := range z.files {
+		if f.Name == name {
+			return z.DeleteIndex(i)
+		}
+	}
+	return errors.New("entry with given name not found")
+}

+ 191 - 0
vendor/github.com/Unknwon/com/LICENSE

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

+ 20 - 0
vendor/github.com/Unknwon/com/README.md

@@ -0,0 +1,20 @@
+Common Functions
+================
+
+[![Build Status](https://travis-ci.org/Unknwon/com.svg)](https://travis-ci.org/Unknwon/com) [![Go Walker](http://gowalker.org/api/v1/badge)](http://gowalker.org/github.com/Unknwon/com)
+
+This is an open source project for commonly used functions for the Go programming language.
+
+This package need >= **go 1.2**
+
+Code Convention: based on [Go Code Convention](https://github.com/Unknwon/go-code-convention).
+
+## Contribute
+
+Your contribute is welcome, but you have to check following steps after you added some functions and commit them:
+
+1. Make sure you wrote user-friendly comments for **all functions** .
+2. Make sure you wrote test cases with any possible condition for **all functions** in file `*_test.go`.
+3. Make sure you wrote benchmarks for **all functions** in file `*_test.go`.
+4. Make sure you wrote useful examples for **all functions** in file `example_test.go`.
+5. Make sure you ran `go test` and got **PASS** .

+ 161 - 0
vendor/github.com/Unknwon/com/cmd.go

@@ -0,0 +1,161 @@
+// +build go1.2
+
+// Copyright 2013 com authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+// Package com is an open source project for commonly used functions for the Go programming language.
+package com
+
+import (
+	"bytes"
+	"fmt"
+	"os/exec"
+	"runtime"
+	"strings"
+)
+
+// ExecCmdDirBytes executes system command in given directory
+// and return stdout, stderr in bytes type, along with possible error.
+func ExecCmdDirBytes(dir, cmdName string, args ...string) ([]byte, []byte, error) {
+	bufOut := new(bytes.Buffer)
+	bufErr := new(bytes.Buffer)
+
+	cmd := exec.Command(cmdName, args...)
+	cmd.Dir = dir
+	cmd.Stdout = bufOut
+	cmd.Stderr = bufErr
+
+	err := cmd.Run()
+	return bufOut.Bytes(), bufErr.Bytes(), err
+}
+
+// ExecCmdBytes executes system command
+// and return stdout, stderr in bytes type, along with possible error.
+func ExecCmdBytes(cmdName string, args ...string) ([]byte, []byte, error) {
+	return ExecCmdDirBytes("", cmdName, args...)
+}
+
+// ExecCmdDir executes system command in given directory
+// and return stdout, stderr in string type, along with possible error.
+func ExecCmdDir(dir, cmdName string, args ...string) (string, string, error) {
+	bufOut, bufErr, err := ExecCmdDirBytes(dir, cmdName, args...)
+	return string(bufOut), string(bufErr), err
+}
+
+// ExecCmd executes system command
+// and return stdout, stderr in string type, along with possible error.
+func ExecCmd(cmdName string, args ...string) (string, string, error) {
+	return ExecCmdDir("", cmdName, args...)
+}
+
+// _________        .__                 .____
+// \_   ___ \  ____ |  |   ___________  |    |    ____   ____
+// /    \  \/ /  _ \|  |  /  _ \_  __ \ |    |   /  _ \ / ___\
+// \     \___(  <_> )  |_(  <_> )  | \/ |    |__(  <_> ) /_/  >
+//  \______  /\____/|____/\____/|__|    |_______ \____/\___  /
+//         \/                                   \/    /_____/
+
+// Color number constants.
+const (
+	Gray = uint8(iota + 90)
+	Red
+	Green
+	Yellow
+	Blue
+	Magenta
+	//NRed      = uint8(31) // Normal
+	EndColor = "\033[0m"
+)
+
+// getColorLevel returns colored level string by given level.
+func getColorLevel(level string) string {
+	level = strings.ToUpper(level)
+	switch level {
+	case "TRAC":
+		return fmt.Sprintf("\033[%dm%s\033[0m", Blue, level)
+	case "ERRO":
+		return fmt.Sprintf("\033[%dm%s\033[0m", Red, level)
+	case "WARN":
+		return fmt.Sprintf("\033[%dm%s\033[0m", Magenta, level)
+	case "SUCC":
+		return fmt.Sprintf("\033[%dm%s\033[0m", Green, level)
+	default:
+		return level
+	}
+}
+
+// ColorLogS colors log and return colored content.
+// Log format: <level> <content [highlight][path]> [ error ].
+// Level: TRAC -> blue; ERRO -> red; WARN -> Magenta; SUCC -> green; others -> default.
+// Content: default; path: yellow; error -> red.
+// Level has to be surrounded by "[" and "]".
+// Highlights have to be surrounded by "# " and " #"(space), "#" will be deleted.
+// Paths have to be surrounded by "( " and " )"(space).
+// Errors have to be surrounded by "[ " and " ]"(space).
+// Note: it hasn't support windows yet, contribute is welcome.
+func ColorLogS(format string, a ...interface{}) string {
+	log := fmt.Sprintf(format, a...)
+
+	var clog string
+
+	if runtime.GOOS != "windows" {
+		// Level.
+		i := strings.Index(log, "]")
+		if log[0] == '[' && i > -1 {
+			clog += "[" + getColorLevel(log[1:i]) + "]"
+		}
+
+		log = log[i+1:]
+
+		// Error.
+		log = strings.Replace(log, "[ ", fmt.Sprintf("[\033[%dm", Red), -1)
+		log = strings.Replace(log, " ]", EndColor+"]", -1)
+
+		// Path.
+		log = strings.Replace(log, "( ", fmt.Sprintf("(\033[%dm", Yellow), -1)
+		log = strings.Replace(log, " )", EndColor+")", -1)
+
+		// Highlights.
+		log = strings.Replace(log, "# ", fmt.Sprintf("\033[%dm", Gray), -1)
+		log = strings.Replace(log, " #", EndColor, -1)
+
+	} else {
+		// Level.
+		i := strings.Index(log, "]")
+		if log[0] == '[' && i > -1 {
+			clog += "[" + log[1:i] + "]"
+		}
+
+		log = log[i+1:]
+
+		// Error.
+		log = strings.Replace(log, "[ ", "[", -1)
+		log = strings.Replace(log, " ]", "]", -1)
+
+		// Path.
+		log = strings.Replace(log, "( ", "(", -1)
+		log = strings.Replace(log, " )", ")", -1)
+
+		// Highlights.
+		log = strings.Replace(log, "# ", "", -1)
+		log = strings.Replace(log, " #", "", -1)
+	}
+	return clog + log
+}
+
+// ColorLog prints colored log to stdout.
+// See color rules in function 'ColorLogS'.
+func ColorLog(format string, a ...interface{}) {
+	fmt.Print(ColorLogS(format, a...))
+}

+ 157 - 0
vendor/github.com/Unknwon/com/convert.go

@@ -0,0 +1,157 @@
+// Copyright 2014 com authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package com
+
+import (
+	"fmt"
+	"strconv"
+)
+
+// Convert string to specify type.
+type StrTo string
+
+func (f StrTo) Exist() bool {
+	return string(f) != string(0x1E)
+}
+
+func (f StrTo) Uint8() (uint8, error) {
+	v, err := strconv.ParseUint(f.String(), 10, 8)
+	return uint8(v), err
+}
+
+func (f StrTo) Int() (int, error) {
+	v, err := strconv.ParseInt(f.String(), 10, 0)
+	return int(v), err
+}
+
+func (f StrTo) Int64() (int64, error) {
+	v, err := strconv.ParseInt(f.String(), 10, 64)
+	return int64(v), err
+}
+
+func (f StrTo) MustUint8() uint8 {
+	v, _ := f.Uint8()
+	return v
+}
+
+func (f StrTo) MustInt() int {
+	v, _ := f.Int()
+	return v
+}
+
+func (f StrTo) MustInt64() int64 {
+	v, _ := f.Int64()
+	return v
+}
+
+func (f StrTo) String() string {
+	if f.Exist() {
+		return string(f)
+	}
+	return ""
+}
+
+// Convert any type to string.
+func ToStr(value interface{}, args ...int) (s string) {
+	switch v := value.(type) {
+	case bool:
+		s = strconv.FormatBool(v)
+	case float32:
+		s = strconv.FormatFloat(float64(v), 'f', argInt(args).Get(0, -1), argInt(args).Get(1, 32))
+	case float64:
+		s = strconv.FormatFloat(v, 'f', argInt(args).Get(0, -1), argInt(args).Get(1, 64))
+	case int:
+		s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10))
+	case int8:
+		s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10))
+	case int16:
+		s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10))
+	case int32:
+		s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10))
+	case int64:
+		s = strconv.FormatInt(v, argInt(args).Get(0, 10))
+	case uint:
+		s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10))
+	case uint8:
+		s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10))
+	case uint16:
+		s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10))
+	case uint32:
+		s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10))
+	case uint64:
+		s = strconv.FormatUint(v, argInt(args).Get(0, 10))
+	case string:
+		s = v
+	case []byte:
+		s = string(v)
+	default:
+		s = fmt.Sprintf("%v", v)
+	}
+	return s
+}
+
+type argInt []int
+
+func (a argInt) Get(i int, args ...int) (r int) {
+	if i >= 0 && i < len(a) {
+		r = a[i]
+	} else if len(args) > 0 {
+		r = args[0]
+	}
+	return
+}
+
+// HexStr2int converts hex format string to decimal number.
+func HexStr2int(hexStr string) (int, error) {
+	num := 0
+	length := len(hexStr)
+	for i := 0; i < length; i++ {
+		char := hexStr[length-i-1]
+		factor := -1
+
+		switch {
+		case char >= '0' && char <= '9':
+			factor = int(char) - '0'
+		case char >= 'a' && char <= 'f':
+			factor = int(char) - 'a' + 10
+		default:
+			return -1, fmt.Errorf("invalid hex: %s", string(char))
+		}
+
+		num += factor * PowInt(16, i)
+	}
+	return num, nil
+}
+
+// Int2HexStr converts decimal number to hex format string.
+func Int2HexStr(num int) (hex string) {
+	if num == 0 {
+		return "0"
+	}
+
+	for num > 0 {
+		r := num % 16
+
+		c := "?"
+		if r >= 0 && r <= 9 {
+			c = string(r + '0')
+		} else {
+			c = string(r + 'a' - 10)
+		}
+		hex = c + hex
+		num = num / 16
+	}
+	return hex
+}

+ 173 - 0
vendor/github.com/Unknwon/com/dir.go

@@ -0,0 +1,173 @@
+// Copyright 2013 com authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package com
+
+import (
+	"errors"
+	"fmt"
+	"os"
+	"path"
+	"strings"
+)
+
+// IsDir returns true if given path is a directory,
+// or returns false when it's a file or does not exist.
+func IsDir(dir string) bool {
+	f, e := os.Stat(dir)
+	if e != nil {
+		return false
+	}
+	return f.IsDir()
+}
+
+func statDir(dirPath, recPath string, includeDir, isDirOnly bool) ([]string, error) {
+	dir, err := os.Open(dirPath)
+	if err != nil {
+		return nil, err
+	}
+	defer dir.Close()
+
+	fis, err := dir.Readdir(0)
+	if err != nil {
+		return nil, err
+	}
+
+	statList := make([]string, 0)
+	for _, fi := range fis {
+		if strings.Contains(fi.Name(), ".DS_Store") {
+			continue
+		}
+
+		relPath := path.Join(recPath, fi.Name())
+		curPath := path.Join(dirPath, fi.Name())
+		if fi.IsDir() {
+			if includeDir {
+				statList = append(statList, relPath+"/")
+			}
+			s, err := statDir(curPath, relPath, includeDir, isDirOnly)
+			if err != nil {
+				return nil, err
+			}
+			statList = append(statList, s...)
+		} else if !isDirOnly {
+			statList = append(statList, relPath)
+		}
+	}
+	return statList, nil
+}
+
+// StatDir gathers information of given directory by depth-first.
+// It returns slice of file list and includes subdirectories if enabled;
+// it returns error and nil slice when error occurs in underlying functions,
+// or given path is not a directory or does not exist.
+//
+// Slice does not include given path itself.
+// If subdirectories is enabled, they will have suffix '/'.
+func StatDir(rootPath string, includeDir ...bool) ([]string, error) {
+	if !IsDir(rootPath) {
+		return nil, errors.New("not a directory or does not exist: " + rootPath)
+	}
+
+	isIncludeDir := false
+	if len(includeDir) >= 1 {
+		isIncludeDir = includeDir[0]
+	}
+	return statDir(rootPath, "", isIncludeDir, false)
+}
+
+// GetAllSubDirs returns all subdirectories of given root path.
+// Slice does not include given path itself.
+func GetAllSubDirs(rootPath string) ([]string, error) {
+	if !IsDir(rootPath) {
+		return nil, errors.New("not a directory or does not exist: " + rootPath)
+	}
+	return statDir(rootPath, "", true, true)
+}
+
+// GetFileListBySuffix returns an ordered list of file paths.
+// It recognize if given path is a file, and don't do recursive find.
+func GetFileListBySuffix(dirPath, suffix string) ([]string, error) {
+	if !IsExist(dirPath) {
+		return nil, fmt.Errorf("given path does not exist: %s", dirPath)
+	} else if IsFile(dirPath) {
+		return []string{dirPath}, nil
+	}
+
+	// Given path is a directory.
+	dir, err := os.Open(dirPath)
+	if err != nil {
+		return nil, err
+	}
+
+	fis, err := dir.Readdir(0)
+	if err != nil {
+		return nil, err
+	}
+
+	files := make([]string, 0, len(fis))
+	for _, fi := range fis {
+		if strings.HasSuffix(fi.Name(), suffix) {
+			files = append(files, path.Join(dirPath, fi.Name()))
+		}
+	}
+
+	return files, nil
+}
+
+// CopyDir copy files recursively from source to target directory.
+//
+// The filter accepts a function that process the path info.
+// and should return true for need to filter.
+//
+// It returns error when error occurs in underlying functions.
+func CopyDir(srcPath, destPath string, filters ...func(filePath string) bool) error {
+	// Check if target directory exists.
+	if IsExist(destPath) {
+		return errors.New("file or directory alreay exists: " + destPath)
+	}
+
+	err := os.MkdirAll(destPath, os.ModePerm)
+	if err != nil {
+		return err
+	}
+
+	// Gather directory info.
+	infos, err := StatDir(srcPath, true)
+	if err != nil {
+		return err
+	}
+
+	var filter func(filePath string) bool
+	if len(filters) > 0 {
+		filter = filters[0]
+	}
+
+	for _, info := range infos {
+		if filter != nil && filter(info) {
+			continue
+		}
+
+		curPath := path.Join(destPath, info)
+		if strings.HasSuffix(info, "/") {
+			err = os.MkdirAll(curPath, os.ModePerm)
+		} else {
+			err = Copy(path.Join(srcPath, info), curPath)
+		}
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}

+ 145 - 0
vendor/github.com/Unknwon/com/file.go

@@ -0,0 +1,145 @@
+// Copyright 2013 com authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package com
+
+import (
+	"fmt"
+	"io"
+	"io/ioutil"
+	"math"
+	"os"
+	"path"
+)
+
+// Storage unit constants.
+const (
+	Byte  = 1
+	KByte = Byte * 1024
+	MByte = KByte * 1024
+	GByte = MByte * 1024
+	TByte = GByte * 1024
+	PByte = TByte * 1024
+	EByte = PByte * 1024
+)
+
+func logn(n, b float64) float64 {
+	return math.Log(n) / math.Log(b)
+}
+
+func humanateBytes(s uint64, base float64, sizes []string) string {
+	if s < 10 {
+		return fmt.Sprintf("%dB", s)
+	}
+	e := math.Floor(logn(float64(s), base))
+	suffix := sizes[int(e)]
+	val := float64(s) / math.Pow(base, math.Floor(e))
+	f := "%.0f"
+	if val < 10 {
+		f = "%.1f"
+	}
+
+	return fmt.Sprintf(f+"%s", val, suffix)
+}
+
+// HumaneFileSize calculates the file size and generate user-friendly string.
+func HumaneFileSize(s uint64) string {
+	sizes := []string{"B", "KB", "MB", "GB", "TB", "PB", "EB"}
+	return humanateBytes(s, 1024, sizes)
+}
+
+// FileMTime returns file modified time and possible error.
+func FileMTime(file string) (int64, error) {
+	f, err := os.Stat(file)
+	if err != nil {
+		return 0, err
+	}
+	return f.ModTime().Unix(), nil
+}
+
+// FileSize returns file size in bytes and possible error.
+func FileSize(file string) (int64, error) {
+	f, err := os.Stat(file)
+	if err != nil {
+		return 0, err
+	}
+	return f.Size(), nil
+}
+
+// Copy copies file from source to target path.
+func Copy(src, dest string) error {
+	// Gather file information to set back later.
+	si, err := os.Lstat(src)
+	if err != nil {
+		return err
+	}
+
+	// Handle symbolic link.
+	if si.Mode()&os.ModeSymlink != 0 {
+		target, err := os.Readlink(src)
+		if err != nil {
+			return err
+		}
+		// NOTE: os.Chmod and os.Chtimes don't recoganize symbolic link,
+		// which will lead "no such file or directory" error.
+		return os.Symlink(target, dest)
+	}
+
+	sr, err := os.Open(src)
+	if err != nil {
+		return err
+	}
+	defer sr.Close()
+
+	dw, err := os.Create(dest)
+	if err != nil {
+		return err
+	}
+	defer dw.Close()
+
+	if _, err = io.Copy(dw, sr); err != nil {
+		return err
+	}
+
+	// Set back file information.
+	if err = os.Chtimes(dest, si.ModTime(), si.ModTime()); err != nil {
+		return err
+	}
+	return os.Chmod(dest, si.Mode())
+}
+
+// WriteFile writes data to a file named by filename.
+// If the file does not exist, WriteFile creates it
+// and its upper level paths.
+func WriteFile(filename string, data []byte) error {
+	os.MkdirAll(path.Dir(filename), os.ModePerm)
+	return ioutil.WriteFile(filename, data, 0655)
+}
+
+// IsFile returns true if given path is a file,
+// or returns false when it's a directory or does not exist.
+func IsFile(filePath string) bool {
+	f, e := os.Stat(filePath)
+	if e != nil {
+		return false
+	}
+	return !f.IsDir()
+}
+
+// IsExist checks whether a file or directory exists.
+// It returns false when the file or directory does not exist.
+func IsExist(path string) bool {
+	_, err := os.Stat(path)
+	return err == nil || os.IsExist(err)
+}

+ 60 - 0
vendor/github.com/Unknwon/com/html.go

@@ -0,0 +1,60 @@
+// Copyright 2013 com authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package com
+
+import (
+	"html"
+	"regexp"
+	"strings"
+)
+
+// Html2JS converts []byte type of HTML content into JS format.
+func Html2JS(data []byte) []byte {
+	s := string(data)
+	s = strings.Replace(s, `\`, `\\`, -1)
+	s = strings.Replace(s, "\n", `\n`, -1)
+	s = strings.Replace(s, "\r", "", -1)
+	s = strings.Replace(s, "\"", `\"`, -1)
+	s = strings.Replace(s, "<table>", "&lt;table>", -1)
+	return []byte(s)
+}
+
+// encode html chars to string
+func HtmlEncode(str string) string {
+	return html.EscapeString(str)
+}
+
+// decode string to html chars
+func HtmlDecode(str string) string {
+	return html.UnescapeString(str)
+}
+
+// strip tags in html string
+func StripTags(src string) string {
+	//去除style,script,html tag
+	re := regexp.MustCompile(`(?s)<(?:style|script)[^<>]*>.*?</(?:style|script)>|</?[a-z][a-z0-9]*[^<>]*>|<!--.*?-->`)
+	src = re.ReplaceAllString(src, "")
+
+	//trim all spaces(2+) into \n
+	re = regexp.MustCompile(`\s{2,}`)
+	src = re.ReplaceAllString(src, "\n")
+
+	return strings.TrimSpace(src)
+}
+
+// change \n to <br/>
+func Nl2br(str string) string {
+	return strings.Replace(str, "\n", "<br/>", -1)
+}

+ 201 - 0
vendor/github.com/Unknwon/com/http.go

@@ -0,0 +1,201 @@
+// Copyright 2013 com authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package com
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"net/http"
+	"os"
+	"path"
+)
+
+type NotFoundError struct {
+	Message string
+}
+
+func (e NotFoundError) Error() string {
+	return e.Message
+}
+
+type RemoteError struct {
+	Host string
+	Err  error
+}
+
+func (e *RemoteError) Error() string {
+	return e.Err.Error()
+}
+
+var UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1541.0 Safari/537.36"
+
+// HttpCall makes HTTP method call.
+func HttpCall(client *http.Client, method, url string, header http.Header, body io.Reader) (io.ReadCloser, error) {
+	req, err := http.NewRequest(method, url, body)
+	if err != nil {
+		return nil, err
+	}
+	req.Header.Set("User-Agent", UserAgent)
+	for k, vs := range header {
+		req.Header[k] = vs
+	}
+	resp, err := client.Do(req)
+	if err != nil {
+		return nil, err
+	}
+	if resp.StatusCode == 200 {
+		return resp.Body, nil
+	}
+	resp.Body.Close()
+	if resp.StatusCode == 404 { // 403 can be rate limit error.  || resp.StatusCode == 403 {
+		err = fmt.Errorf("resource not found: %s", url)
+	} else {
+		err = fmt.Errorf("%s %s -> %d", method, url, resp.StatusCode)
+	}
+	return nil, err
+}
+
+// HttpGet gets the specified resource.
+// ErrNotFound is returned if the server responds with status 404.
+func HttpGet(client *http.Client, url string, header http.Header) (io.ReadCloser, error) {
+	return HttpCall(client, "GET", url, header, nil)
+}
+
+// HttpPost posts the specified resource.
+// ErrNotFound is returned if the server responds with status 404.
+func HttpPost(client *http.Client, url string, header http.Header, body []byte) (io.ReadCloser, error) {
+	return HttpCall(client, "POST", url, header, bytes.NewBuffer(body))
+}
+
+// HttpGetToFile gets the specified resource and writes to file.
+// ErrNotFound is returned if the server responds with status 404.
+func HttpGetToFile(client *http.Client, url string, header http.Header, fileName string) error {
+	rc, err := HttpGet(client, url, header)
+	if err != nil {
+		return err
+	}
+	defer rc.Close()
+
+	os.MkdirAll(path.Dir(fileName), os.ModePerm)
+	f, err := os.Create(fileName)
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+	_, err = io.Copy(f, rc)
+	return err
+}
+
+// HttpGetBytes gets the specified resource. ErrNotFound is returned if the server
+// responds with status 404.
+func HttpGetBytes(client *http.Client, url string, header http.Header) ([]byte, error) {
+	rc, err := HttpGet(client, url, header)
+	if err != nil {
+		return nil, err
+	}
+	defer rc.Close()
+	return ioutil.ReadAll(rc)
+}
+
+// HttpGetJSON gets the specified resource and mapping to struct.
+// ErrNotFound is returned if the server responds with status 404.
+func HttpGetJSON(client *http.Client, url string, v interface{}) error {
+	rc, err := HttpGet(client, url, nil)
+	if err != nil {
+		return err
+	}
+	defer rc.Close()
+	err = json.NewDecoder(rc).Decode(v)
+	if _, ok := err.(*json.SyntaxError); ok {
+		return fmt.Errorf("JSON syntax error at %s", url)
+	}
+	return nil
+}
+
+// HttpPostJSON posts the specified resource with struct values,
+// and maps results to struct.
+// ErrNotFound is returned if the server responds with status 404.
+func HttpPostJSON(client *http.Client, url string, body, v interface{}) error {
+	data, err := json.Marshal(body)
+	if err != nil {
+		return err
+	}
+	rc, err := HttpPost(client, url, http.Header{"content-type": []string{"application/json"}}, data)
+	if err != nil {
+		return err
+	}
+	defer rc.Close()
+	err = json.NewDecoder(rc).Decode(v)
+	if _, ok := err.(*json.SyntaxError); ok {
+		return fmt.Errorf("JSON syntax error at %s", url)
+	}
+	return nil
+}
+
+// A RawFile describes a file that can be downloaded.
+type RawFile interface {
+	Name() string
+	RawUrl() string
+	Data() []byte
+	SetData([]byte)
+}
+
+// FetchFiles fetches files specified by the rawURL field in parallel.
+func FetchFiles(client *http.Client, files []RawFile, header http.Header) error {
+	ch := make(chan error, len(files))
+	for i := range files {
+		go func(i int) {
+			p, err := HttpGetBytes(client, files[i].RawUrl(), nil)
+			if err != nil {
+				ch <- err
+				return
+			}
+			files[i].SetData(p)
+			ch <- nil
+		}(i)
+	}
+	for _ = range files {
+		if err := <-ch; err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// FetchFiles uses command `curl` to fetch files specified by the rawURL field in parallel.
+func FetchFilesCurl(files []RawFile, curlOptions ...string) error {
+	ch := make(chan error, len(files))
+	for i := range files {
+		go func(i int) {
+			stdout, _, err := ExecCmd("curl", append(curlOptions, files[i].RawUrl())...)
+			if err != nil {
+				ch <- err
+				return
+			}
+
+			files[i].SetData([]byte(stdout))
+			ch <- nil
+		}(i)
+	}
+	for _ = range files {
+		if err := <-ch; err != nil {
+			return err
+		}
+	}
+	return nil
+}

+ 29 - 0
vendor/github.com/Unknwon/com/math.go

@@ -0,0 +1,29 @@
+// Copyright 2014 com authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package com
+
+// PowInt is int type of math.Pow function. 
+func PowInt(x int, y int) int {
+	if y <= 0 {
+		return 1
+	} else {
+		if y % 2 == 0 {
+			sqrt := PowInt(x, y/2)
+			return sqrt * sqrt
+		} else {
+			return PowInt(x, y-1) * x
+		}
+	}
+}

+ 80 - 0
vendor/github.com/Unknwon/com/path.go

@@ -0,0 +1,80 @@
+// Copyright 2013 com authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package com
+
+import (
+	"errors"
+	"os"
+	"path/filepath"
+	"runtime"
+	"strings"
+)
+
+// GetGOPATHs returns all paths in GOPATH variable.
+func GetGOPATHs() []string {
+	gopath := os.Getenv("GOPATH")
+	var paths []string
+	if runtime.GOOS == "windows" {
+		gopath = strings.Replace(gopath, "\\", "/", -1)
+		paths = strings.Split(gopath, ";")
+	} else {
+		paths = strings.Split(gopath, ":")
+	}
+	return paths
+}
+
+// GetSrcPath returns app. source code path.
+// It only works when you have src. folder in GOPATH,
+// it returns error not able to locate source folder path.
+func GetSrcPath(importPath string) (appPath string, err error) {
+	paths := GetGOPATHs()
+	for _, p := range paths {
+		if IsExist(p + "/src/" + importPath + "/") {
+			appPath = p + "/src/" + importPath + "/"
+			break
+		}
+	}
+
+	if len(appPath) == 0 {
+		return "", errors.New("Unable to locate source folder path")
+	}
+
+	appPath = filepath.Dir(appPath) + "/"
+	if runtime.GOOS == "windows" {
+		// Replace all '\' to '/'.
+		appPath = strings.Replace(appPath, "\\", "/", -1)
+	}
+
+	return appPath, nil
+}
+
+// HomeDir returns path of '~'(in Linux) on Windows,
+// it returns error when the variable does not exist.
+func HomeDir() (home string, err error) {
+	if runtime.GOOS == "windows" {
+		home = os.Getenv("USERPROFILE")
+		if len(home) == 0 {
+			home = os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
+		}
+	} else {
+		home = os.Getenv("HOME")
+	}
+
+	if len(home) == 0 {
+		return "", errors.New("Cannot specify home directory because it's empty")
+	}
+
+	return home, nil
+}

+ 56 - 0
vendor/github.com/Unknwon/com/regex.go

@@ -0,0 +1,56 @@
+// Copyright 2013 com authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package com
+
+import "regexp"
+
+const (
+	regex_email_pattern        = `(?i)[A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,6}`
+	regex_strict_email_pattern = `(?i)[A-Z0-9!#$%&'*+/=?^_{|}~-]+` +
+		`(?:\.[A-Z0-9!#$%&'*+/=?^_{|}~-]+)*` +
+		`@(?:[A-Z0-9](?:[A-Z0-9-]*[A-Z0-9])?\.)+` +
+		`[A-Z0-9](?:[A-Z0-9-]*[A-Z0-9])?`
+	regex_url_pattern = `(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?`
+)
+
+var (
+	regex_email        *regexp.Regexp
+	regex_strict_email *regexp.Regexp
+	regex_url          *regexp.Regexp
+)
+
+func init() {
+	regex_email = regexp.MustCompile(regex_email_pattern)
+	regex_strict_email = regexp.MustCompile(regex_strict_email_pattern)
+	regex_url = regexp.MustCompile(regex_url_pattern)
+}
+
+// validate string is an email address, if not return false
+// basically validation can match 99% cases
+func IsEmail(email string) bool {
+	return regex_email.MatchString(email)
+}
+
+// validate string is an email address, if not return false
+// this validation omits RFC 2822
+func IsEmailRFC(email string) bool {
+	return regex_strict_email.MatchString(email)
+}
+
+// validate string is a url link, if not return false
+// simple validation can match 99% cases
+func IsUrl(url string) bool {
+	return regex_url.MatchString(url)
+}

+ 87 - 0
vendor/github.com/Unknwon/com/slice.go

@@ -0,0 +1,87 @@
+// Copyright 2013 com authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package com
+
+import (
+	"strings"
+)
+
+// AppendStr appends string to slice with no duplicates.
+func AppendStr(strs []string, str string) []string {
+	for _, s := range strs {
+		if s == str {
+			return strs
+		}
+	}
+	return append(strs, str)
+}
+
+// CompareSliceStr compares two 'string' type slices.
+// It returns true if elements and order are both the same.
+func CompareSliceStr(s1, s2 []string) bool {
+	if len(s1) != len(s2) {
+		return false
+	}
+
+	for i := range s1 {
+		if s1[i] != s2[i] {
+			return false
+		}
+	}
+
+	return true
+}
+
+// CompareSliceStr compares two 'string' type slices.
+// It returns true if elements are the same, and ignores the order.
+func CompareSliceStrU(s1, s2 []string) bool {
+	if len(s1) != len(s2) {
+		return false
+	}
+
+	for i := range s1 {
+		for j := len(s2) - 1; j >= 0; j-- {
+			if s1[i] == s2[j] {
+				s2 = append(s2[:j], s2[j+1:]...)
+				break
+			}
+		}
+	}
+	if len(s2) > 0 {
+		return false
+	}
+	return true
+}
+
+// IsSliceContainsStr returns true if the string exists in given slice, ignore case.
+func IsSliceContainsStr(sl []string, str string) bool {
+	str = strings.ToLower(str)
+	for _, s := range sl {
+		if strings.ToLower(s) == str {
+			return true
+		}
+	}
+	return false
+}
+
+// IsSliceContainsInt64 returns true if the int64 exists in given slice.
+func IsSliceContainsInt64(sl []int64, i int64) bool {
+	for _, s := range sl {
+		if s == i {
+			return true
+		}
+	}
+	return false
+}

+ 243 - 0
vendor/github.com/Unknwon/com/string.go

@@ -0,0 +1,243 @@
+// Copyright 2013 com authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package com
+
+import (
+	"bytes"
+	"crypto/aes"
+	"crypto/cipher"
+	"crypto/rand"
+	"encoding/base64"
+	"errors"
+	"io"
+	r "math/rand"
+	"strconv"
+	"strings"
+	"time"
+	"unicode"
+	"unicode/utf8"
+)
+
+// AESEncrypt encrypts text and given key with AES.
+func AESEncrypt(key, text []byte) ([]byte, error) {
+	block, err := aes.NewCipher(key)
+	if err != nil {
+		return nil, err
+	}
+	b := base64.StdEncoding.EncodeToString(text)
+	ciphertext := make([]byte, aes.BlockSize+len(b))
+	iv := ciphertext[:aes.BlockSize]
+	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
+		return nil, err
+	}
+	cfb := cipher.NewCFBEncrypter(block, iv)
+	cfb.XORKeyStream(ciphertext[aes.BlockSize:], []byte(b))
+	return ciphertext, nil
+}
+
+// AESDecrypt decrypts text and given key with AES.
+func AESDecrypt(key, text []byte) ([]byte, error) {
+	block, err := aes.NewCipher(key)
+	if err != nil {
+		return nil, err
+	}
+	if len(text) < aes.BlockSize {
+		return nil, errors.New("ciphertext too short")
+	}
+	iv := text[:aes.BlockSize]
+	text = text[aes.BlockSize:]
+	cfb := cipher.NewCFBDecrypter(block, iv)
+	cfb.XORKeyStream(text, text)
+	data, err := base64.StdEncoding.DecodeString(string(text))
+	if err != nil {
+		return nil, err
+	}
+	return data, nil
+}
+
+// IsLetter returns true if the 'l' is an English letter.
+func IsLetter(l uint8) bool {
+	n := (l | 0x20) - 'a'
+	if n >= 0 && n < 26 {
+		return true
+	}
+	return false
+}
+
+// Expand replaces {k} in template with match[k] or subs[atoi(k)] if k is not in match.
+func Expand(template string, match map[string]string, subs ...string) string {
+	var p []byte
+	var i int
+	for {
+		i = strings.Index(template, "{")
+		if i < 0 {
+			break
+		}
+		p = append(p, template[:i]...)
+		template = template[i+1:]
+		i = strings.Index(template, "}")
+		if s, ok := match[template[:i]]; ok {
+			p = append(p, s...)
+		} else {
+			j, _ := strconv.Atoi(template[:i])
+			if j >= len(subs) {
+				p = append(p, []byte("Missing")...)
+			} else {
+				p = append(p, subs[j]...)
+			}
+		}
+		template = template[i+1:]
+	}
+	p = append(p, template...)
+	return string(p)
+}
+
+// Reverse s string, support unicode
+func Reverse(s string) string {
+	n := len(s)
+	runes := make([]rune, n)
+	for _, rune := range s {
+		n--
+		runes[n] = rune
+	}
+	return string(runes[n:])
+}
+
+// RandomCreateBytes generate random []byte by specify chars.
+func RandomCreateBytes(n int, alphabets ...byte) []byte {
+	const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+	var bytes = make([]byte, n)
+	var randby bool
+	if num, err := rand.Read(bytes); num != n || err != nil {
+		r.Seed(time.Now().UnixNano())
+		randby = true
+	}
+	for i, b := range bytes {
+		if len(alphabets) == 0 {
+			if randby {
+				bytes[i] = alphanum[r.Intn(len(alphanum))]
+			} else {
+				bytes[i] = alphanum[b%byte(len(alphanum))]
+			}
+		} else {
+			if randby {
+				bytes[i] = alphabets[r.Intn(len(alphabets))]
+			} else {
+				bytes[i] = alphabets[b%byte(len(alphabets))]
+			}
+		}
+	}
+	return bytes
+}
+
+// ToSnakeCase can convert all upper case characters in a string to
+// underscore format.
+//
+// Some samples.
+//     "FirstName"  => "first_name"
+//     "HTTPServer" => "http_server"
+//     "NoHTTPS"    => "no_https"
+//     "GO_PATH"    => "go_path"
+//     "GO PATH"    => "go_path"      // space is converted to underscore.
+//     "GO-PATH"    => "go_path"      // hyphen is converted to underscore.
+//
+// From https://github.com/huandu/xstrings
+func ToSnakeCase(str string) string {
+	if len(str) == 0 {
+		return ""
+	}
+
+	buf := &bytes.Buffer{}
+	var prev, r0, r1 rune
+	var size int
+
+	r0 = '_'
+
+	for len(str) > 0 {
+		prev = r0
+		r0, size = utf8.DecodeRuneInString(str)
+		str = str[size:]
+
+		switch {
+		case r0 == utf8.RuneError:
+			buf.WriteByte(byte(str[0]))
+
+		case unicode.IsUpper(r0):
+			if prev != '_' {
+				buf.WriteRune('_')
+			}
+
+			buf.WriteRune(unicode.ToLower(r0))
+
+			if len(str) == 0 {
+				break
+			}
+
+			r0, size = utf8.DecodeRuneInString(str)
+			str = str[size:]
+
+			if !unicode.IsUpper(r0) {
+				buf.WriteRune(r0)
+				break
+			}
+
+			// find next non-upper-case character and insert `_` properly.
+			// it's designed to convert `HTTPServer` to `http_server`.
+			// if there are more than 2 adjacent upper case characters in a word,
+			// treat them as an abbreviation plus a normal word.
+			for len(str) > 0 {
+				r1 = r0
+				r0, size = utf8.DecodeRuneInString(str)
+				str = str[size:]
+
+				if r0 == utf8.RuneError {
+					buf.WriteRune(unicode.ToLower(r1))
+					buf.WriteByte(byte(str[0]))
+					break
+				}
+
+				if !unicode.IsUpper(r0) {
+					if r0 == '_' || r0 == ' ' || r0 == '-' {
+						r0 = '_'
+
+						buf.WriteRune(unicode.ToLower(r1))
+					} else {
+						buf.WriteRune('_')
+						buf.WriteRune(unicode.ToLower(r1))
+						buf.WriteRune(r0)
+					}
+
+					break
+				}
+
+				buf.WriteRune(unicode.ToLower(r1))
+			}
+
+			if len(str) == 0 || r0 == '_' {
+				buf.WriteRune(unicode.ToLower(r0))
+				break
+			}
+
+		default:
+			if r0 == ' ' || r0 == '-' {
+				r0 = '_'
+			}
+
+			buf.WriteRune(r0)
+		}
+	}
+
+	return buf.String()
+}

+ 115 - 0
vendor/github.com/Unknwon/com/time.go

@@ -0,0 +1,115 @@
+// Copyright 2013 com authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package com
+
+import (
+	"fmt"
+	"strconv"
+	"strings"
+	"time"
+)
+
+// Format unix time int64 to string
+func Date(ti int64, format string) string {
+	t := time.Unix(int64(ti), 0)
+	return DateT(t, format)
+}
+
+// Format unix time string to string
+func DateS(ts string, format string) string {
+	i, _ := strconv.ParseInt(ts, 10, 64)
+	return Date(i, format)
+}
+
+// Format time.Time struct to string
+// MM - month - 01
+// M - month - 1, single bit
+// DD - day - 02
+// D - day 2
+// YYYY - year - 2006
+// YY - year - 06
+// HH - 24 hours - 03
+// H - 24 hours - 3
+// hh - 12 hours - 03
+// h - 12 hours - 3
+// mm - minute - 04
+// m - minute - 4
+// ss - second - 05
+// s - second = 5
+func DateT(t time.Time, format string) string {
+	res := strings.Replace(format, "MM", t.Format("01"), -1)
+	res = strings.Replace(res, "M", t.Format("1"), -1)
+	res = strings.Replace(res, "DD", t.Format("02"), -1)
+	res = strings.Replace(res, "D", t.Format("2"), -1)
+	res = strings.Replace(res, "YYYY", t.Format("2006"), -1)
+	res = strings.Replace(res, "YY", t.Format("06"), -1)
+	res = strings.Replace(res, "HH", fmt.Sprintf("%02d", t.Hour()), -1)
+	res = strings.Replace(res, "H", fmt.Sprintf("%d", t.Hour()), -1)
+	res = strings.Replace(res, "hh", t.Format("03"), -1)
+	res = strings.Replace(res, "h", t.Format("3"), -1)
+	res = strings.Replace(res, "mm", t.Format("04"), -1)
+	res = strings.Replace(res, "m", t.Format("4"), -1)
+	res = strings.Replace(res, "ss", t.Format("05"), -1)
+	res = strings.Replace(res, "s", t.Format("5"), -1)
+	return res
+}
+
+// DateFormat pattern rules.
+var datePatterns = []string{
+	// year
+	"Y", "2006", // A full numeric representation of a year, 4 digits   Examples: 1999 or 2003
+	"y", "06", //A two digit representation of a year   Examples: 99 or 03
+
+	// month
+	"m", "01", // Numeric representation of a month, with leading zeros 01 through 12
+	"n", "1", // Numeric representation of a month, without leading zeros   1 through 12
+	"M", "Jan", // A short textual representation of a month, three letters Jan through Dec
+	"F", "January", // A full textual representation of a month, such as January or March   January through December
+
+	// day
+	"d", "02", // Day of the month, 2 digits with leading zeros 01 to 31
+	"j", "2", // Day of the month without leading zeros 1 to 31
+
+	// week
+	"D", "Mon", // A textual representation of a day, three letters Mon through Sun
+	"l", "Monday", // A full textual representation of the day of the week  Sunday through Saturday
+
+	// time
+	"g", "3", // 12-hour format of an hour without leading zeros    1 through 12
+	"G", "15", // 24-hour format of an hour without leading zeros   0 through 23
+	"h", "03", // 12-hour format of an hour with leading zeros  01 through 12
+	"H", "15", // 24-hour format of an hour with leading zeros  00 through 23
+
+	"a", "pm", // Lowercase Ante meridiem and Post meridiem am or pm
+	"A", "PM", // Uppercase Ante meridiem and Post meridiem AM or PM
+
+	"i", "04", // Minutes with leading zeros    00 to 59
+	"s", "05", // Seconds, with leading zeros   00 through 59
+
+	// time zone
+	"T", "MST",
+	"P", "-07:00",
+	"O", "-0700",
+
+	// RFC 2822
+	"r", time.RFC1123Z,
+}
+
+// Parse Date use PHP time format.
+func DateParse(dateString, format string) (time.Time, error) {
+	replacer := strings.NewReplacer(datePatterns...)
+	format = replacer.Replace(format)
+	return time.ParseInLocation(format, dateString, time.Local)
+}

+ 41 - 0
vendor/github.com/Unknwon/com/url.go

@@ -0,0 +1,41 @@
+// Copyright 2013 com authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package com
+
+import (
+	"encoding/base64"
+	"net/url"
+)
+
+// url encode string, is + not %20
+func UrlEncode(str string) string {
+	return url.QueryEscape(str)
+}
+
+// url decode string
+func UrlDecode(str string) (string, error) {
+	return url.QueryUnescape(str)
+}
+
+// base64 encode
+func Base64Encode(str string) string {
+	return base64.StdEncoding.EncodeToString([]byte(str))
+}
+
+// base64 decode
+func Base64Decode(str string) (string, error) {
+	s, e := base64.StdEncoding.DecodeString(str)
+	return string(s), e
+}

+ 191 - 0
vendor/github.com/Unknwon/i18n/LICENSE

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

+ 134 - 0
vendor/github.com/Unknwon/i18n/README.md

@@ -0,0 +1,134 @@
+i18n
+====
+
+Package i18n is for app Internationalization and Localization.
+
+## Introduction
+
+This package provides multiple-language options to improve user experience. Sites like [Go Walker](http://gowalker.org) and [gogs.io](http://gogs.io) are using this module to implement Chinese and English user interfaces.
+
+You can use following command to install this module:
+
+    go get github.com/Unknwon/i18n
+
+## Usage
+
+First of all, you have to import this package:
+
+```go
+import "github.com/Unknwon/i18n"
+```
+
+The format of locale files is very like INI format configuration file, which is basically key-value pairs. But this module has some improvements. Every language corresponding to a locale file, for example, under `conf/locale` folder of [gogsweb](https://github.com/gogits/gogsweb/tree/master/conf/locale), there are two files called `locale_en-US.ini` and `locale_zh-CN.ini`.
+
+The name and extensions of locale files can be anything, but we strongly recommend you to follow the style of gogsweb.
+
+## Minimal example
+
+Here are two simplest locale file examples:
+
+File `locale_en-US.ini`:
+
+```ini
+hi = hello, %s
+bye = goodbye
+```
+
+File `locale_zh-CN.ini`:
+
+```ini
+hi = 您好,%s
+bye = 再见
+```
+
+### Do Translation
+
+There are two ways to do translation depends on which way is the best fit for your application or framework.
+
+Directly use package function to translate:
+
+```go
+i18n.Tr("en-US", "hi", "Unknwon")
+i18n.Tr("en-US", "bye")
+```
+
+Or create a struct and embed it:
+
+```go
+type MyController struct{
+    // ...other fields
+    i18n.Locale
+}
+
+//...
+
+func ... {
+    c := &MyController{
+        Locale: i18n.Locale{"en-US"},
+    }
+    _ = c.Tr("hi", "Unknwon")
+    _ = c.Tr("bye")
+}
+```
+
+Code above will produce correspondingly:
+
+- English `en-US`:`hello, Unknwon`, `goodbye`
+- Chinese `zh-CN`:`您好,Unknwon`, `再见`
+
+## Section
+
+For different pages, one key may map to different values. Therefore, i18n module also uses the section feature of INI format configuration to achieve section.
+
+For example, the key name is `about`, and we want to show `About` in the home page and `About Us` in about page. Then you can do following:
+
+Content in locale file:
+
+```ini
+about = About
+
+[about]
+about = About Us
+```
+
+Get `about` in home page:
+
+```go
+i18n.Tr("en-US", "about")
+```
+
+Get `about` in about page:
+
+```go
+i18n.Tr("en-US", "about.about")
+```
+
+### Ambiguity
+
+Because dot `.` is sign of section in both [INI parser](https://github.com/go-ini/ini) and locale files, so when your key name contains `.` will cause ambiguity. At this point, you just need to add one more `.` in front of the key.
+
+For example, the key name is `about.`, then we can use:
+
+```go
+i18n.Tr("en-US", ".about.")
+```
+
+to get expect result.
+
+## Helper tool
+
+Module i18n provides a command line helper tool beei18n for simplify steps of your development. You can install it as follows:
+
+	go get github.com/Unknwon/i18n/ui18n
+
+### Sync locale files
+
+Command `sync` allows you use a exist local file as the template to create or sync other locale files:
+
+	ui18n sync srouce_file.ini other1.ini other2.ini
+
+This command can operate 1 or more files in one command.
+
+## More information
+
+If the key does not exist, then i18n will return the key string to caller. For instance, when key name is `hi` and it does not exist in locale file, simply return `hi` as output.

+ 225 - 0
vendor/github.com/Unknwon/i18n/i18n.go

@@ -0,0 +1,225 @@
+// Copyright 2013 Unknwon
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+// Package i18n is for app Internationalization and Localization.
+package i18n
+
+import (
+	"errors"
+	"fmt"
+	"reflect"
+	"strings"
+
+	"gopkg.in/ini.v1"
+)
+
+var (
+	ErrLangAlreadyExist = errors.New("Lang already exists")
+
+	locales = &localeStore{store: make(map[string]*locale)}
+)
+
+type locale struct {
+	id       int
+	lang     string
+	langDesc string
+	message  *ini.File
+}
+
+type localeStore struct {
+	langs       []string
+	langDescs   []string
+	store       map[string]*locale
+	defaultLang string
+}
+
+// Get target language string
+func (d *localeStore) Get(lang, section, format string) (string, bool) {
+	if locale, ok := d.store[lang]; ok {
+		if key, err := locale.message.Section(section).GetKey(format); err == nil {
+			return key.Value(), true
+		}
+	}
+
+	if len(d.defaultLang) > 0 && lang != d.defaultLang {
+		return d.Get(d.defaultLang, section, format)
+	}
+
+	return "", false
+}
+
+func (d *localeStore) Add(lc *locale) bool {
+	if _, ok := d.store[lc.lang]; ok {
+		return false
+	}
+
+	lc.id = len(d.langs)
+	d.langs = append(d.langs, lc.lang)
+	d.langDescs = append(d.langDescs, lc.langDesc)
+	d.store[lc.lang] = lc
+
+	return true
+}
+
+func (d *localeStore) Reload(langs ...string) (err error) {
+	if len(langs) == 0 {
+		for _, lc := range d.store {
+			if err = lc.message.Reload(); err != nil {
+				return err
+			}
+		}
+	} else {
+		for _, lang := range langs {
+			if lc, ok := d.store[lang]; ok {
+				if err = lc.message.Reload(); err != nil {
+					return err
+				}
+			}
+		}
+	}
+	return nil
+}
+
+// SetDefaultLang sets default language which is a indicator that
+// when target language is not found, try find in default language again.
+func SetDefaultLang(lang string) {
+	locales.defaultLang = lang
+}
+
+// ReloadLangs reloads locale files.
+func ReloadLangs(langs ...string) error {
+	return locales.Reload(langs...)
+}
+
+// Count returns number of languages that are registered.
+func Count() int {
+	return len(locales.langs)
+}
+
+// ListLangs returns list of all locale languages.
+func ListLangs() []string {
+	langs := make([]string, len(locales.langs))
+	copy(langs, locales.langs)
+	return langs
+}
+
+func ListLangDescs() []string {
+	langDescs := make([]string, len(locales.langDescs))
+	copy(langDescs, locales.langDescs)
+	return langDescs
+}
+
+// IsExist returns true if given language locale exists.
+func IsExist(lang string) bool {
+	_, ok := locales.store[lang]
+	return ok
+}
+
+// IndexLang returns index of language locale,
+// it returns -1 if locale not exists.
+func IndexLang(lang string) int {
+	if lc, ok := locales.store[lang]; ok {
+		return lc.id
+	}
+	return -1
+}
+
+// GetLangByIndex return language by given index.
+func GetLangByIndex(index int) string {
+	if index < 0 || index >= len(locales.langs) {
+		return ""
+	}
+	return locales.langs[index]
+}
+
+func GetDescriptionByIndex(index int) string {
+	if index < 0 || index >= len(locales.langDescs) {
+		return ""
+	}
+
+	return locales.langDescs[index]
+}
+
+func GetDescriptionByLang(lang string) string {
+	return GetDescriptionByIndex(IndexLang(lang))
+}
+
+func SetMessageWithDesc(lang, langDesc string, localeFile interface{}, otherLocaleFiles ...interface{}) error {
+	message, err := ini.Load(localeFile, otherLocaleFiles...)
+	if err == nil {
+		message.BlockMode = false
+		lc := new(locale)
+		lc.lang = lang
+		lc.langDesc = langDesc
+		lc.message = message
+
+		if locales.Add(lc) == false {
+			return ErrLangAlreadyExist
+		}
+	}
+	return err
+}
+
+// SetMessage sets the message file for localization.
+func SetMessage(lang string, localeFile interface{}, otherLocaleFiles ...interface{}) error {
+	return SetMessageWithDesc(lang, lang, localeFile, otherLocaleFiles...)
+}
+
+// Locale represents the information of localization.
+type Locale struct {
+	Lang string
+}
+
+// Tr translates content to target language.
+func (l Locale) Tr(format string, args ...interface{}) string {
+	return Tr(l.Lang, format, args...)
+}
+
+// Index returns lang index of LangStore.
+func (l Locale) Index() int {
+	return IndexLang(l.Lang)
+}
+
+// Tr translates content to target language.
+func Tr(lang, format string, args ...interface{}) string {
+	var section string
+	parts := strings.SplitN(format, ".", 2)
+	if len(parts) == 2 {
+		section = parts[0]
+		format = parts[1]
+	}
+
+	value, ok := locales.Get(lang, section, format)
+	if ok {
+		format = value
+	}
+
+	if len(args) > 0 {
+		params := make([]interface{}, 0, len(args))
+		for _, arg := range args {
+			if arg != nil {
+				val := reflect.ValueOf(arg)
+				if val.Kind() == reflect.Slice {
+					for i := 0; i < val.Len(); i++ {
+						params = append(params, val.Index(i).Interface())
+					}
+				} else {
+					params = append(params, arg)
+				}
+			}
+		}
+		return fmt.Sprintf(format, params...)
+	}
+	return format
+}

+ 202 - 0
vendor/github.com/Unknwon/paginater/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.
+

+ 65 - 0
vendor/github.com/Unknwon/paginater/README.md

@@ -0,0 +1,65 @@
+Paginater [![Build Status](https://travis-ci.org/Unknwon/paginater.svg?branch=master)](https://travis-ci.org/Unknwon/paginater)
+=========
+
+Package paginater is a helper module for custom pagination calculation.
+
+## Installation
+
+	go get github.com/Unknwon/paginater
+
+## Getting Started
+
+The following code shows an example of how to use paginater:
+
+```go
+package main
+
+import "github.com/Unknwon/paginater"
+
+func main() {
+	// Arguments:
+	// - Total number of rows
+	// - Number of rows in one page
+	// - Current page number 
+	// - Number of page links to be displayed
+	p := paginater.New(45, 10, 3, 3)
+	
+	// Then use p as a template object named "Page" in "demo.html"
+	// ...
+}
+```
+
+`demo.html`
+
+```html
+{{if not .Page.IsFirst}}[First](1){{end}}
+{{if .Page.HasPrevious}}[Previous]({{.Page.Previous}}){{end}}
+
+{{range .Page.Pages}}
+	{{if eq .Num -1}}
+	...
+	{{else}}
+	{{.Num}}{{if .IsCurrent}}(current){{end}}
+	{{end}}
+{{end}}
+
+{{if .Page.HasNext}}[Next]({{.Page.Next}}){{end}}
+{{if not .Page.IsLast}}[Last]({{.Page.TotalPages}}){{end}}
+```
+
+Possible output:
+
+```
+[First](1) [Previous](2) ... 2 3(current) 4 ... [Next](4) [Last](5)
+```
+
+As you may guess, if the `Page` value is `-1`, you should print `...` in the HTML as common practice.
+
+## Getting Help
+
+- [API Documentation](https://gowalker.org/github.com/Unknwon/paginater)
+- [File An Issue](https://github.com/Unknwon/paginater/issues/new)
+
+## License
+
+This project is under Apache v2 License. See the [LICENSE](LICENSE) file for the full license text.

+ 197 - 0
vendor/github.com/Unknwon/paginater/paginater.go

@@ -0,0 +1,197 @@
+// Copyright 2015 Unknwon
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+// Package paginater is a helper module for custom pagination calculation.
+package paginater
+
+// Paginater represents a set of results of pagination calculations.
+type Paginater struct {
+	total     int
+	pagingNum int
+	current   int
+	numPages  int
+}
+
+// New initialize a new pagination calculation and returns a Paginater as result.
+func New(total, pagingNum, current, numPages int) *Paginater {
+	if pagingNum <= 0 {
+		pagingNum = 1
+	}
+	if current <= 0 {
+		current = 1
+	}
+	p := &Paginater{total, pagingNum, current, numPages}
+	if p.current > p.TotalPages() {
+		p.current = p.TotalPages()
+	}
+	return p
+}
+
+// IsFirst returns true if current page is the first page.
+func (p *Paginater) IsFirst() bool {
+	return p.current == 1
+}
+
+// HasPrevious returns true if there is a previous page relative to current page.
+func (p *Paginater) HasPrevious() bool {
+	return p.current > 1
+}
+
+func (p *Paginater) Previous() int {
+	if !p.HasPrevious() {
+		return p.current
+	}
+	return p.current - 1
+}
+
+// HasNext returns true if there is a next page relative to current page.
+func (p *Paginater) HasNext() bool {
+	return p.total > p.current*p.pagingNum
+}
+
+func (p *Paginater) Next() int {
+	if !p.HasNext() {
+		return p.current
+	}
+	return p.current + 1
+}
+
+// IsLast returns true if current page is the last page.
+func (p *Paginater) IsLast() bool {
+	if p.total == 0 {
+		return true
+	}
+	return p.total > (p.current-1)*p.pagingNum && !p.HasNext()
+}
+
+// Total returns number of total rows.
+func (p *Paginater) Total() int {
+	return p.total
+}
+
+// TotalPage returns number of total pages.
+func (p *Paginater) TotalPages() int {
+	if p.total == 0 {
+		return 1
+	}
+	if p.total%p.pagingNum == 0 {
+		return p.total / p.pagingNum
+	}
+	return p.total/p.pagingNum + 1
+}
+
+// Current returns current page number.
+func (p *Paginater) Current() int {
+	return p.current
+}
+
+// PagingNum returns number of page size.
+func (p *Paginater) PagingNum() int {
+	return p.pagingNum
+}
+
+// Page presents a page in the paginater.
+type Page struct {
+	num       int
+	isCurrent bool
+}
+
+func (p *Page) Num() int {
+	return p.num
+}
+
+func (p *Page) IsCurrent() bool {
+	return p.isCurrent
+}
+
+func getMiddleIdx(numPages int) int {
+	if numPages%2 == 0 {
+		return numPages / 2
+	}
+	return numPages/2 + 1
+}
+
+// Pages returns a list of nearby page numbers relative to current page.
+// If value is -1 means "..." that more pages are not showing.
+func (p *Paginater) Pages() []*Page {
+	if p.numPages == 0 {
+		return []*Page{}
+	} else if p.numPages == 1 && p.TotalPages() == 1 {
+		// Only show current page.
+		return []*Page{{1, true}}
+	}
+
+	// Total page number is less or equal.
+	if p.TotalPages() <= p.numPages {
+		pages := make([]*Page, p.TotalPages())
+		for i := range pages {
+			pages[i] = &Page{i + 1, i+1 == p.current}
+		}
+		return pages
+	}
+
+	numPages := p.numPages
+	maxIdx := numPages - 1
+	offsetIdx := 0
+	hasMoreNext := false
+
+	// Check more previous and next pages.
+	previousNum := getMiddleIdx(p.numPages) - 1
+	if previousNum > p.current-1 {
+		previousNum -= previousNum - (p.current - 1)
+	}
+	nextNum := p.numPages - previousNum - 1
+	if p.current+nextNum > p.TotalPages() {
+		delta := nextNum - (p.TotalPages() - p.current)
+		nextNum -= delta
+		previousNum += delta
+	}
+
+	offsetVal := p.current - previousNum
+	if offsetVal > 1 {
+		numPages++
+		maxIdx++
+		offsetIdx = 1
+	}
+
+	if p.current+nextNum < p.TotalPages() {
+		numPages++
+		hasMoreNext = true
+	}
+
+	pages := make([]*Page, numPages)
+
+	// There are more previous pages.
+	if offsetIdx == 1 {
+		pages[0] = &Page{-1, false}
+	}
+	// There are more next pages.
+	if hasMoreNext {
+		pages[len(pages)-1] = &Page{-1, false}
+	}
+
+	// Check previous pages.
+	for i := 0; i < previousNum; i++ {
+		pages[offsetIdx+i] = &Page{i + offsetVal, false}
+	}
+
+	pages[offsetIdx+previousNum] = &Page{p.current, true}
+
+	// Check next pages.
+	for i := 1; i <= nextNum; i++ {
+		pages[offsetIdx+previousNum+i] = &Page{p.current + i, false}
+	}
+
+	return pages
+}

+ 202 - 0
vendor/github.com/bradfitz/gomemcache/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.

+ 666 - 0
vendor/github.com/bradfitz/gomemcache/memcache/memcache.go

@@ -0,0 +1,666 @@
+/*
+Copyright 2011 Google Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package memcache provides a client for the memcached cache server.
+package memcache
+
+import (
+	"bufio"
+	"bytes"
+	"errors"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"net"
+
+	"strconv"
+	"strings"
+	"sync"
+	"time"
+)
+
+// Similar to:
+// http://code.google.com/appengine/docs/go/memcache/reference.html
+
+var (
+	// ErrCacheMiss means that a Get failed because the item wasn't present.
+	ErrCacheMiss = errors.New("memcache: cache miss")
+
+	// ErrCASConflict means that a CompareAndSwap call failed due to the
+	// cached value being modified between the Get and the CompareAndSwap.
+	// If the cached value was simply evicted rather than replaced,
+	// ErrNotStored will be returned instead.
+	ErrCASConflict = errors.New("memcache: compare-and-swap conflict")
+
+	// ErrNotStored means that a conditional write operation (i.e. Add or
+	// CompareAndSwap) failed because the condition was not satisfied.
+	ErrNotStored = errors.New("memcache: item not stored")
+
+	// ErrServer means that a server error occurred.
+	ErrServerError = errors.New("memcache: server error")
+
+	// ErrNoStats means that no statistics were available.
+	ErrNoStats = errors.New("memcache: no statistics available")
+
+	// ErrMalformedKey is returned when an invalid key is used.
+	// Keys must be at maximum 250 bytes long, ASCII, and not
+	// contain whitespace or control characters.
+	ErrMalformedKey = errors.New("malformed: key is too long or contains invalid characters")
+
+	// ErrNoServers is returned when no servers are configured or available.
+	ErrNoServers = errors.New("memcache: no servers configured or available")
+)
+
+// DefaultTimeout is the default socket read/write timeout.
+const DefaultTimeout = 100 * time.Millisecond
+
+const (
+	buffered            = 8 // arbitrary buffered channel size, for readability
+	maxIdleConnsPerAddr = 2 // TODO(bradfitz): make this configurable?
+)
+
+// resumableError returns true if err is only a protocol-level cache error.
+// This is used to determine whether or not a server connection should
+// be re-used or not. If an error occurs, by default we don't reuse the
+// connection, unless it was just a cache error.
+func resumableError(err error) bool {
+	switch err {
+	case ErrCacheMiss, ErrCASConflict, ErrNotStored, ErrMalformedKey:
+		return true
+	}
+	return false
+}
+
+func legalKey(key string) bool {
+	if len(key) > 250 {
+		return false
+	}
+	for i := 0; i < len(key); i++ {
+		if key[i] <= ' ' || key[i] > 0x7e {
+			return false
+		}
+	}
+	return true
+}
+
+var (
+	crlf            = []byte("\r\n")
+	space           = []byte(" ")
+	resultOK        = []byte("OK\r\n")
+	resultStored    = []byte("STORED\r\n")
+	resultNotStored = []byte("NOT_STORED\r\n")
+	resultExists    = []byte("EXISTS\r\n")
+	resultNotFound  = []byte("NOT_FOUND\r\n")
+	resultDeleted   = []byte("DELETED\r\n")
+	resultEnd       = []byte("END\r\n")
+	resultOk        = []byte("OK\r\n")
+	resultTouched   = []byte("TOUCHED\r\n")
+
+	resultClientErrorPrefix = []byte("CLIENT_ERROR ")
+)
+
+// New returns a memcache client using the provided server(s)
+// with equal weight. If a server is listed multiple times,
+// it gets a proportional amount of weight.
+func New(server ...string) *Client {
+	ss := new(ServerList)
+	ss.SetServers(server...)
+	return NewFromSelector(ss)
+}
+
+// NewFromSelector returns a new Client using the provided ServerSelector.
+func NewFromSelector(ss ServerSelector) *Client {
+	return &Client{selector: ss}
+}
+
+// Client is a memcache client.
+// It is safe for unlocked use by multiple concurrent goroutines.
+type Client struct {
+	// Timeout specifies the socket read/write timeout.
+	// If zero, DefaultTimeout is used.
+	Timeout time.Duration
+
+	selector ServerSelector
+
+	lk       sync.Mutex
+	freeconn map[string][]*conn
+}
+
+// Item is an item to be got or stored in a memcached server.
+type Item struct {
+	// Key is the Item's key (250 bytes maximum).
+	Key string
+
+	// Value is the Item's value.
+	Value []byte
+
+	// Flags are server-opaque flags whose semantics are entirely
+	// up to the app.
+	Flags uint32
+
+	// Expiration is the cache expiration time, in seconds: either a relative
+	// time from now (up to 1 month), or an absolute Unix epoch time.
+	// Zero means the Item has no expiration time.
+	Expiration int32
+
+	// Compare and swap ID.
+	casid uint64
+}
+
+// conn is a connection to a server.
+type conn struct {
+	nc   net.Conn
+	rw   *bufio.ReadWriter
+	addr net.Addr
+	c    *Client
+}
+
+// release returns this connection back to the client's free pool
+func (cn *conn) release() {
+	cn.c.putFreeConn(cn.addr, cn)
+}
+
+func (cn *conn) extendDeadline() {
+	cn.nc.SetDeadline(time.Now().Add(cn.c.netTimeout()))
+}
+
+// condRelease releases this connection if the error pointed to by err
+// is nil (not an error) or is only a protocol level error (e.g. a
+// cache miss).  The purpose is to not recycle TCP connections that
+// are bad.
+func (cn *conn) condRelease(err *error) {
+	if *err == nil || resumableError(*err) {
+		cn.release()
+	} else {
+		cn.nc.Close()
+	}
+}
+
+func (c *Client) putFreeConn(addr net.Addr, cn *conn) {
+	c.lk.Lock()
+	defer c.lk.Unlock()
+	if c.freeconn == nil {
+		c.freeconn = make(map[string][]*conn)
+	}
+	freelist := c.freeconn[addr.String()]
+	if len(freelist) >= maxIdleConnsPerAddr {
+		cn.nc.Close()
+		return
+	}
+	c.freeconn[addr.String()] = append(freelist, cn)
+}
+
+func (c *Client) getFreeConn(addr net.Addr) (cn *conn, ok bool) {
+	c.lk.Lock()
+	defer c.lk.Unlock()
+	if c.freeconn == nil {
+		return nil, false
+	}
+	freelist, ok := c.freeconn[addr.String()]
+	if !ok || len(freelist) == 0 {
+		return nil, false
+	}
+	cn = freelist[len(freelist)-1]
+	c.freeconn[addr.String()] = freelist[:len(freelist)-1]
+	return cn, true
+}
+
+func (c *Client) netTimeout() time.Duration {
+	if c.Timeout != 0 {
+		return c.Timeout
+	}
+	return DefaultTimeout
+}
+
+// ConnectTimeoutError is the error type used when it takes
+// too long to connect to the desired host. This level of
+// detail can generally be ignored.
+type ConnectTimeoutError struct {
+	Addr net.Addr
+}
+
+func (cte *ConnectTimeoutError) Error() string {
+	return "memcache: connect timeout to " + cte.Addr.String()
+}
+
+func (c *Client) dial(addr net.Addr) (net.Conn, error) {
+	type connError struct {
+		cn  net.Conn
+		err error
+	}
+
+	nc, err := net.DialTimeout(addr.Network(), addr.String(), c.netTimeout())
+	if err == nil {
+		return nc, nil
+	}
+
+	if ne, ok := err.(net.Error); ok && ne.Timeout() {
+		return nil, &ConnectTimeoutError{addr}
+	}
+
+	return nil, err
+}
+
+func (c *Client) getConn(addr net.Addr) (*conn, error) {
+	cn, ok := c.getFreeConn(addr)
+	if ok {
+		cn.extendDeadline()
+		return cn, nil
+	}
+	nc, err := c.dial(addr)
+	if err != nil {
+		return nil, err
+	}
+	cn = &conn{
+		nc:   nc,
+		addr: addr,
+		rw:   bufio.NewReadWriter(bufio.NewReader(nc), bufio.NewWriter(nc)),
+		c:    c,
+	}
+	cn.extendDeadline()
+	return cn, nil
+}
+
+func (c *Client) onItem(item *Item, fn func(*Client, *bufio.ReadWriter, *Item) error) error {
+	addr, err := c.selector.PickServer(item.Key)
+	if err != nil {
+		return err
+	}
+	cn, err := c.getConn(addr)
+	if err != nil {
+		return err
+	}
+	defer cn.condRelease(&err)
+	if err = fn(c, cn.rw, item); err != nil {
+		return err
+	}
+	return nil
+}
+
+func (c *Client) FlushAll() error {
+	return c.selector.Each(c.flushAllFromAddr)
+}
+
+// Get gets the item for the given key. ErrCacheMiss is returned for a
+// memcache cache miss. The key must be at most 250 bytes in length.
+func (c *Client) Get(key string) (item *Item, err error) {
+	err = c.withKeyAddr(key, func(addr net.Addr) error {
+		return c.getFromAddr(addr, []string{key}, func(it *Item) { item = it })
+	})
+	if err == nil && item == nil {
+		err = ErrCacheMiss
+	}
+	return
+}
+
+// Touch updates the expiry for the given key. The seconds parameter is either
+// a Unix timestamp or, if seconds is less than 1 month, the number of seconds
+// into the future at which time the item will expire. ErrCacheMiss is returned if the
+// key is not in the cache. The key must be at most 250 bytes in length.
+func (c *Client) Touch(key string, seconds int32) (err error) {
+	return c.withKeyAddr(key, func(addr net.Addr) error {
+		return c.touchFromAddr(addr, []string{key}, seconds)
+	})
+}
+
+func (c *Client) withKeyAddr(key string, fn func(net.Addr) error) (err error) {
+	if !legalKey(key) {
+		return ErrMalformedKey
+	}
+	addr, err := c.selector.PickServer(key)
+	if err != nil {
+		return err
+	}
+	return fn(addr)
+}
+
+func (c *Client) withAddrRw(addr net.Addr, fn func(*bufio.ReadWriter) error) (err error) {
+	cn, err := c.getConn(addr)
+	if err != nil {
+		return err
+	}
+	defer cn.condRelease(&err)
+	return fn(cn.rw)
+}
+
+func (c *Client) withKeyRw(key string, fn func(*bufio.ReadWriter) error) error {
+	return c.withKeyAddr(key, func(addr net.Addr) error {
+		return c.withAddrRw(addr, fn)
+	})
+}
+
+func (c *Client) getFromAddr(addr net.Addr, keys []string, cb func(*Item)) error {
+	return c.withAddrRw(addr, func(rw *bufio.ReadWriter) error {
+		if _, err := fmt.Fprintf(rw, "gets %s\r\n", strings.Join(keys, " ")); err != nil {
+			return err
+		}
+		if err := rw.Flush(); err != nil {
+			return err
+		}
+		if err := parseGetResponse(rw.Reader, cb); err != nil {
+			return err
+		}
+		return nil
+	})
+}
+
+// flushAllFromAddr send the flush_all command to the given addr
+func (c *Client) flushAllFromAddr(addr net.Addr) error {
+	return c.withAddrRw(addr, func(rw *bufio.ReadWriter) error {
+		if _, err := fmt.Fprintf(rw, "flush_all\r\n"); err != nil {
+			return err
+		}
+		if err := rw.Flush(); err != nil {
+			return err
+		}
+		line, err := rw.ReadSlice('\n')
+		if err != nil {
+			return err
+		}
+		switch {
+		case bytes.Equal(line, resultOk):
+			break
+		default:
+			return fmt.Errorf("memcache: unexpected response line from flush_all: %q", string(line))
+		}
+		return nil
+	})
+}
+
+func (c *Client) touchFromAddr(addr net.Addr, keys []string, expiration int32) error {
+	return c.withAddrRw(addr, func(rw *bufio.ReadWriter) error {
+		for _, key := range keys {
+			if _, err := fmt.Fprintf(rw, "touch %s %d\r\n", key, expiration); err != nil {
+				return err
+			}
+			if err := rw.Flush(); err != nil {
+				return err
+			}
+			line, err := rw.ReadSlice('\n')
+			if err != nil {
+				return err
+			}
+			switch {
+			case bytes.Equal(line, resultTouched):
+				break
+			case bytes.Equal(line, resultNotFound):
+				return ErrCacheMiss
+			default:
+				return fmt.Errorf("memcache: unexpected response line from touch: %q", string(line))
+			}
+		}
+		return nil
+	})
+}
+
+// GetMulti is a batch version of Get. The returned map from keys to
+// items may have fewer elements than the input slice, due to memcache
+// cache misses. Each key must be at most 250 bytes in length.
+// If no error is returned, the returned map will also be non-nil.
+func (c *Client) GetMulti(keys []string) (map[string]*Item, error) {
+	var lk sync.Mutex
+	m := make(map[string]*Item)
+	addItemToMap := func(it *Item) {
+		lk.Lock()
+		defer lk.Unlock()
+		m[it.Key] = it
+	}
+
+	keyMap := make(map[net.Addr][]string)
+	for _, key := range keys {
+		if !legalKey(key) {
+			return nil, ErrMalformedKey
+		}
+		addr, err := c.selector.PickServer(key)
+		if err != nil {
+			return nil, err
+		}
+		keyMap[addr] = append(keyMap[addr], key)
+	}
+
+	ch := make(chan error, buffered)
+	for addr, keys := range keyMap {
+		go func(addr net.Addr, keys []string) {
+			ch <- c.getFromAddr(addr, keys, addItemToMap)
+		}(addr, keys)
+	}
+
+	var err error
+	for _ = range keyMap {
+		if ge := <-ch; ge != nil {
+			err = ge
+		}
+	}
+	return m, err
+}
+
+// parseGetResponse reads a GET response from r and calls cb for each
+// read and allocated Item
+func parseGetResponse(r *bufio.Reader, cb func(*Item)) error {
+	for {
+		line, err := r.ReadSlice('\n')
+		if err != nil {
+			return err
+		}
+		if bytes.Equal(line, resultEnd) {
+			return nil
+		}
+		it := new(Item)
+		size, err := scanGetResponseLine(line, it)
+		if err != nil {
+			return err
+		}
+		it.Value, err = ioutil.ReadAll(io.LimitReader(r, int64(size)+2))
+		if err != nil {
+			return err
+		}
+		if !bytes.HasSuffix(it.Value, crlf) {
+			return fmt.Errorf("memcache: corrupt get result read")
+		}
+		it.Value = it.Value[:size]
+		cb(it)
+	}
+}
+
+// scanGetResponseLine populates it and returns the declared size of the item.
+// It does not read the bytes of the item.
+func scanGetResponseLine(line []byte, it *Item) (size int, err error) {
+	pattern := "VALUE %s %d %d %d\r\n"
+	dest := []interface{}{&it.Key, &it.Flags, &size, &it.casid}
+	if bytes.Count(line, space) == 3 {
+		pattern = "VALUE %s %d %d\r\n"
+		dest = dest[:3]
+	}
+	n, err := fmt.Sscanf(string(line), pattern, dest...)
+	if err != nil || n != len(dest) {
+		return -1, fmt.Errorf("memcache: unexpected line in get response: %q", line)
+	}
+	return size, nil
+}
+
+// Set writes the given item, unconditionally.
+func (c *Client) Set(item *Item) error {
+	return c.onItem(item, (*Client).set)
+}
+
+func (c *Client) set(rw *bufio.ReadWriter, item *Item) error {
+	return c.populateOne(rw, "set", item)
+}
+
+// Add writes the given item, if no value already exists for its
+// key. ErrNotStored is returned if that condition is not met.
+func (c *Client) Add(item *Item) error {
+	return c.onItem(item, (*Client).add)
+}
+
+func (c *Client) add(rw *bufio.ReadWriter, item *Item) error {
+	return c.populateOne(rw, "add", item)
+}
+
+// Replace writes the given item, but only if the server *does*
+// already hold data for this key
+func (c *Client) Replace(item *Item) error {
+	return c.onItem(item, (*Client).replace)
+}
+
+func (c *Client) replace(rw *bufio.ReadWriter, item *Item) error {
+	return c.populateOne(rw, "replace", item)
+}
+
+// CompareAndSwap writes the given item that was previously returned
+// by Get, if the value was neither modified or evicted between the
+// Get and the CompareAndSwap calls. The item's Key should not change
+// between calls but all other item fields may differ. ErrCASConflict
+// is returned if the value was modified in between the
+// calls. ErrNotStored is returned if the value was evicted in between
+// the calls.
+func (c *Client) CompareAndSwap(item *Item) error {
+	return c.onItem(item, (*Client).cas)
+}
+
+func (c *Client) cas(rw *bufio.ReadWriter, item *Item) error {
+	return c.populateOne(rw, "cas", item)
+}
+
+func (c *Client) populateOne(rw *bufio.ReadWriter, verb string, item *Item) error {
+	if !legalKey(item.Key) {
+		return ErrMalformedKey
+	}
+	var err error
+	if verb == "cas" {
+		_, err = fmt.Fprintf(rw, "%s %s %d %d %d %d\r\n",
+			verb, item.Key, item.Flags, item.Expiration, len(item.Value), item.casid)
+	} else {
+		_, err = fmt.Fprintf(rw, "%s %s %d %d %d\r\n",
+			verb, item.Key, item.Flags, item.Expiration, len(item.Value))
+	}
+	if err != nil {
+		return err
+	}
+	if _, err = rw.Write(item.Value); err != nil {
+		return err
+	}
+	if _, err := rw.Write(crlf); err != nil {
+		return err
+	}
+	if err := rw.Flush(); err != nil {
+		return err
+	}
+	line, err := rw.ReadSlice('\n')
+	if err != nil {
+		return err
+	}
+	switch {
+	case bytes.Equal(line, resultStored):
+		return nil
+	case bytes.Equal(line, resultNotStored):
+		return ErrNotStored
+	case bytes.Equal(line, resultExists):
+		return ErrCASConflict
+	case bytes.Equal(line, resultNotFound):
+		return ErrCacheMiss
+	}
+	return fmt.Errorf("memcache: unexpected response line from %q: %q", verb, string(line))
+}
+
+func writeReadLine(rw *bufio.ReadWriter, format string, args ...interface{}) ([]byte, error) {
+	_, err := fmt.Fprintf(rw, format, args...)
+	if err != nil {
+		return nil, err
+	}
+	if err := rw.Flush(); err != nil {
+		return nil, err
+	}
+	line, err := rw.ReadSlice('\n')
+	return line, err
+}
+
+func writeExpectf(rw *bufio.ReadWriter, expect []byte, format string, args ...interface{}) error {
+	line, err := writeReadLine(rw, format, args...)
+	if err != nil {
+		return err
+	}
+	switch {
+	case bytes.Equal(line, resultOK):
+		return nil
+	case bytes.Equal(line, expect):
+		return nil
+	case bytes.Equal(line, resultNotStored):
+		return ErrNotStored
+	case bytes.Equal(line, resultExists):
+		return ErrCASConflict
+	case bytes.Equal(line, resultNotFound):
+		return ErrCacheMiss
+	}
+	return fmt.Errorf("memcache: unexpected response line: %q", string(line))
+}
+
+// Delete deletes the item with the provided key. The error ErrCacheMiss is
+// returned if the item didn't already exist in the cache.
+func (c *Client) Delete(key string) error {
+	return c.withKeyRw(key, func(rw *bufio.ReadWriter) error {
+		return writeExpectf(rw, resultDeleted, "delete %s\r\n", key)
+	})
+}
+
+// DeleteAll deletes all items in the cache.
+func (c *Client) DeleteAll() error {
+	return c.withKeyRw("", func(rw *bufio.ReadWriter) error {
+		return writeExpectf(rw, resultDeleted, "flush_all\r\n")
+	})
+}
+
+// Increment atomically increments key by delta. The return value is
+// the new value after being incremented or an error. If the value
+// didn't exist in memcached the error is ErrCacheMiss. The value in
+// memcached must be an decimal number, or an error will be returned.
+// On 64-bit overflow, the new value wraps around.
+func (c *Client) Increment(key string, delta uint64) (newValue uint64, err error) {
+	return c.incrDecr("incr", key, delta)
+}
+
+// Decrement atomically decrements key by delta. The return value is
+// the new value after being decremented or an error. If the value
+// didn't exist in memcached the error is ErrCacheMiss. The value in
+// memcached must be an decimal number, or an error will be returned.
+// On underflow, the new value is capped at zero and does not wrap
+// around.
+func (c *Client) Decrement(key string, delta uint64) (newValue uint64, err error) {
+	return c.incrDecr("decr", key, delta)
+}
+
+func (c *Client) incrDecr(verb, key string, delta uint64) (uint64, error) {
+	var val uint64
+	err := c.withKeyRw(key, func(rw *bufio.ReadWriter) error {
+		line, err := writeReadLine(rw, "%s %s %d\r\n", verb, key, delta)
+		if err != nil {
+			return err
+		}
+		switch {
+		case bytes.Equal(line, resultNotFound):
+			return ErrCacheMiss
+		case bytes.HasPrefix(line, resultClientErrorPrefix):
+			errMsg := line[len(resultClientErrorPrefix) : len(line)-2]
+			return errors.New("memcache: client error: " + string(errMsg))
+		}
+		val, err = strconv.ParseUint(string(line[:len(line)-2]), 10, 64)
+		if err != nil {
+			return err
+		}
+		return nil
+	})
+	return val, err
+}

+ 114 - 0
vendor/github.com/bradfitz/gomemcache/memcache/selector.go

@@ -0,0 +1,114 @@
+/*
+Copyright 2011 Google Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package memcache
+
+import (
+	"hash/crc32"
+	"net"
+	"strings"
+	"sync"
+)
+
+// ServerSelector is the interface that selects a memcache server
+// as a function of the item's key.
+//
+// All ServerSelector implementations must be safe for concurrent use
+// by multiple goroutines.
+type ServerSelector interface {
+	// PickServer returns the server address that a given item
+	// should be shared onto.
+	PickServer(key string) (net.Addr, error)
+	Each(func(net.Addr) error) error
+}
+
+// ServerList is a simple ServerSelector. Its zero value is usable.
+type ServerList struct {
+	mu    sync.RWMutex
+	addrs []net.Addr
+}
+
+// SetServers changes a ServerList's set of servers at runtime and is
+// safe for concurrent use by multiple goroutines.
+//
+// Each server is given equal weight. A server is given more weight
+// if it's listed multiple times.
+//
+// SetServers returns an error if any of the server names fail to
+// resolve. No attempt is made to connect to the server. If any error
+// is returned, no changes are made to the ServerList.
+func (ss *ServerList) SetServers(servers ...string) error {
+	naddr := make([]net.Addr, len(servers))
+	for i, server := range servers {
+		if strings.Contains(server, "/") {
+			addr, err := net.ResolveUnixAddr("unix", server)
+			if err != nil {
+				return err
+			}
+			naddr[i] = addr
+		} else {
+			tcpaddr, err := net.ResolveTCPAddr("tcp", server)
+			if err != nil {
+				return err
+			}
+			naddr[i] = tcpaddr
+		}
+	}
+
+	ss.mu.Lock()
+	defer ss.mu.Unlock()
+	ss.addrs = naddr
+	return nil
+}
+
+// Each iterates over each server calling the given function
+func (ss *ServerList) Each(f func(net.Addr) error) error {
+	ss.mu.RLock()
+	defer ss.mu.RUnlock()
+	for _, a := range ss.addrs {
+		if err := f(a); nil != err {
+			return err
+		}
+	}
+	return nil
+}
+
+// keyBufPool returns []byte buffers for use by PickServer's call to
+// crc32.ChecksumIEEE to avoid allocations. (but doesn't avoid the
+// copies, which at least are bounded in size and small)
+var keyBufPool = sync.Pool{
+	New: func() interface{} {
+		b := make([]byte, 256)
+		return &b
+	},
+}
+
+func (ss *ServerList) PickServer(key string) (net.Addr, error) {
+	ss.mu.RLock()
+	defer ss.mu.RUnlock()
+	if len(ss.addrs) == 0 {
+		return nil, ErrNoServers
+	}
+	if len(ss.addrs) == 1 {
+		return ss.addrs[0], nil
+	}
+	bufp := keyBufPool.Get().(*[]byte)
+	n := copy(*bufp, key)
+	cs := crc32.ChecksumIEEE((*bufp)[:n])
+	keyBufPool.Put(bufp)
+
+	return ss.addrs[cs%uint32(len(ss.addrs))], nil
+}

+ 20 - 0
vendor/github.com/fatih/color/LICENSE.md

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

+ 175 - 0
vendor/github.com/fatih/color/README.md

@@ -0,0 +1,175 @@
+# Color [![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](http://godoc.org/github.com/fatih/color) [![Build Status](http://img.shields.io/travis/fatih/color.svg?style=flat-square)](https://travis-ci.org/fatih/color)
+
+
+
+Color lets you use colorized outputs in terms of [ANSI Escape
+Codes](http://en.wikipedia.org/wiki/ANSI_escape_code#Colors) in Go (Golang). It
+has support for Windows too! The API can be used in several ways, pick one that
+suits you.
+
+
+
+![Color](http://i.imgur.com/c1JI0lA.png)
+
+
+## Install
+
+```bash
+go get github.com/fatih/color
+```
+
+## Examples
+
+### Standard colors
+
+```go
+// Print with default helper functions
+color.Cyan("Prints text in cyan.")
+
+// A newline will be appended automatically
+color.Blue("Prints %s in blue.", "text")
+
+// These are using the default foreground colors
+color.Red("We have red")
+color.Magenta("And many others ..")
+
+```
+
+### Mix and reuse colors
+
+```go
+// Create a new color object
+c := color.New(color.FgCyan).Add(color.Underline)
+c.Println("Prints cyan text with an underline.")
+
+// Or just add them to New()
+d := color.New(color.FgCyan, color.Bold)
+d.Printf("This prints bold cyan %s\n", "too!.")
+
+// Mix up foreground and background colors, create new mixes!
+red := color.New(color.FgRed)
+
+boldRed := red.Add(color.Bold)
+boldRed.Println("This will print text in bold red.")
+
+whiteBackground := red.Add(color.BgWhite)
+whiteBackground.Println("Red text with white background.")
+```
+
+### Use your own output (io.Writer)
+
+```go
+// Use your own io.Writer output
+color.New(color.FgBlue).Fprintln(myWriter, "blue color!")
+
+blue := color.New(color.FgBlue)
+blue.Fprint(writer, "This will print text in blue.")
+```
+
+### Custom print functions (PrintFunc)
+
+```go
+// Create a custom print function for convenience
+red := color.New(color.FgRed).PrintfFunc()
+red("Warning")
+red("Error: %s", err)
+
+// Mix up multiple attributes
+notice := color.New(color.Bold, color.FgGreen).PrintlnFunc()
+notice("Don't forget this...")
+```
+
+### Custom fprint functions (FprintFunc)
+
+```go
+blue := color.New(FgBlue).FprintfFunc()
+blue(myWriter, "important notice: %s", stars)
+
+// Mix up with multiple attributes
+success := color.New(color.Bold, color.FgGreen).FprintlnFunc()
+success(myWriter, "Don't forget this...")
+```
+
+### Insert into noncolor strings (SprintFunc)
+
+```go
+// Create SprintXxx functions to mix strings with other non-colorized strings:
+yellow := color.New(color.FgYellow).SprintFunc()
+red := color.New(color.FgRed).SprintFunc()
+fmt.Printf("This is a %s and this is %s.\n", yellow("warning"), red("error"))
+
+info := color.New(color.FgWhite, color.BgGreen).SprintFunc()
+fmt.Printf("This %s rocks!\n", info("package"))
+
+// Use helper functions
+fmt.Println("This", color.RedString("warning"), "should be not neglected.")
+fmt.Printf("%v %v\n", color.GreenString("Info:"), "an important message.")
+
+// Windows supported too! Just don't forget to change the output to color.Output
+fmt.Fprintf(color.Output, "Windows support: %s", color.GreenString("PASS"))
+```
+
+### Plug into existing code
+
+```go
+// Use handy standard colors
+color.Set(color.FgYellow)
+
+fmt.Println("Existing text will now be in yellow")
+fmt.Printf("This one %s\n", "too")
+
+color.Unset() // Don't forget to unset
+
+// You can mix up parameters
+color.Set(color.FgMagenta, color.Bold)
+defer color.Unset() // Use it in your function
+
+fmt.Println("All text will now be bold magenta.")
+```
+
+### Disable color
+
+There might be a case where you want to disable color output (for example to
+pipe the standard output of your app to somewhere else). `Color` has support to
+disable colors both globally and for single color definition. For example
+suppose you have a CLI app and a `--no-color` bool flag. You can easily disable
+the color output with:
+
+```go
+
+var flagNoColor = flag.Bool("no-color", false, "Disable color output")
+
+if *flagNoColor {
+	color.NoColor = true // disables colorized output
+}
+```
+
+It also has support for single color definitions (local). You can
+disable/enable color output on the fly:
+
+```go
+c := color.New(color.FgCyan)
+c.Println("Prints cyan text")
+
+c.DisableColor()
+c.Println("This is printed without any color")
+
+c.EnableColor()
+c.Println("This prints again cyan...")
+```
+
+## Todo
+
+* Save/Return previous values
+* Evaluate fmt.Formatter interface
+
+
+## Credits
+
+ * [Fatih Arslan](https://github.com/fatih)
+ * Windows support via @mattn: [colorable](https://github.com/mattn/go-colorable)
+
+## License
+
+The MIT License (MIT) - see [`LICENSE.md`](https://github.com/fatih/color/blob/master/LICENSE.md) for more details
+

+ 510 - 0
vendor/github.com/fatih/color/color.go

@@ -0,0 +1,510 @@
+package color
+
+import (
+	"fmt"
+	"io"
+	"os"
+	"strconv"
+	"strings"
+	"sync"
+
+	"github.com/mattn/go-colorable"
+	"github.com/mattn/go-isatty"
+)
+
+var (
+	// NoColor defines if the output is colorized or not. It's dynamically set to
+	// false or true based on the stdout's file descriptor referring to a terminal
+	// or not. This is a global option and affects all colors. For more control
+	// over each color block use the methods DisableColor() individually.
+	NoColor = !isatty.IsTerminal(os.Stdout.Fd()) || os.Getenv("TERM") == "dumb"
+
+	// Output defines the standard output of the print functions. By default
+	// os.Stdout is used.
+	Output = colorable.NewColorableStdout()
+
+	// colorsCache is used to reduce the count of created Color objects and
+	// allows to reuse already created objects with required Attribute.
+	colorsCache   = make(map[Attribute]*Color)
+	colorsCacheMu sync.Mutex // protects colorsCache
+)
+
+// Color defines a custom color object which is defined by SGR parameters.
+type Color struct {
+	params  []Attribute
+	noColor *bool
+}
+
+// Attribute defines a single SGR Code
+type Attribute int
+
+const escape = "\x1b"
+
+// Base attributes
+const (
+	Reset Attribute = iota
+	Bold
+	Faint
+	Italic
+	Underline
+	BlinkSlow
+	BlinkRapid
+	ReverseVideo
+	Concealed
+	CrossedOut
+)
+
+// Foreground text colors
+const (
+	FgBlack Attribute = iota + 30
+	FgRed
+	FgGreen
+	FgYellow
+	FgBlue
+	FgMagenta
+	FgCyan
+	FgWhite
+)
+
+// Foreground Hi-Intensity text colors
+const (
+	FgHiBlack Attribute = iota + 90
+	FgHiRed
+	FgHiGreen
+	FgHiYellow
+	FgHiBlue
+	FgHiMagenta
+	FgHiCyan
+	FgHiWhite
+)
+
+// Background text colors
+const (
+	BgBlack Attribute = iota + 40
+	BgRed
+	BgGreen
+	BgYellow
+	BgBlue
+	BgMagenta
+	BgCyan
+	BgWhite
+)
+
+// Background Hi-Intensity text colors
+const (
+	BgHiBlack Attribute = iota + 100
+	BgHiRed
+	BgHiGreen
+	BgHiYellow
+	BgHiBlue
+	BgHiMagenta
+	BgHiCyan
+	BgHiWhite
+)
+
+// New returns a newly created color object.
+func New(value ...Attribute) *Color {
+	c := &Color{params: make([]Attribute, 0)}
+	c.Add(value...)
+	return c
+}
+
+// Set sets the given parameters immediately. It will change the color of
+// output with the given SGR parameters until color.Unset() is called.
+func Set(p ...Attribute) *Color {
+	c := New(p...)
+	c.Set()
+	return c
+}
+
+// Unset resets all escape attributes and clears the output. Usually should
+// be called after Set().
+func Unset() {
+	if NoColor {
+		return
+	}
+
+	fmt.Fprintf(Output, "%s[%dm", escape, Reset)
+}
+
+// Set sets the SGR sequence.
+func (c *Color) Set() *Color {
+	if c.isNoColorSet() {
+		return c
+	}
+
+	fmt.Fprintf(Output, c.format())
+	return c
+}
+
+func (c *Color) unset() {
+	if c.isNoColorSet() {
+		return
+	}
+
+	Unset()
+}
+
+func (c *Color) setWriter(w io.Writer) *Color {
+	if c.isNoColorSet() {
+		return c
+	}
+
+	fmt.Fprintf(w, c.format())
+	return c
+}
+
+func (c *Color) unsetWriter(w io.Writer) {
+	if c.isNoColorSet() {
+		return
+	}
+
+	if NoColor {
+		return
+	}
+
+	fmt.Fprintf(w, "%s[%dm", escape, Reset)
+}
+
+// Add is used to chain SGR parameters. Use as many as parameters to combine
+// and create custom color objects. Example: Add(color.FgRed, color.Underline).
+func (c *Color) Add(value ...Attribute) *Color {
+	c.params = append(c.params, value...)
+	return c
+}
+
+func (c *Color) prepend(value Attribute) {
+	c.params = append(c.params, 0)
+	copy(c.params[1:], c.params[0:])
+	c.params[0] = value
+}
+
+// Fprint formats using the default formats for its operands and writes to w.
+// Spaces are added between operands when neither is a string.
+// It returns the number of bytes written and any write error encountered.
+// On Windows, users should wrap w with colorable.NewColorable() if w is of
+// type *os.File.
+func (c *Color) Fprint(w io.Writer, a ...interface{}) (n int, err error) {
+	c.setWriter(w)
+	defer c.unsetWriter(w)
+
+	return fmt.Fprint(w, a...)
+}
+
+// Print formats using the default formats for its operands and writes to
+// standard output. Spaces are added between operands when neither is a
+// string. It returns the number of bytes written and any write error
+// encountered. This is the standard fmt.Print() method wrapped with the given
+// color.
+func (c *Color) Print(a ...interface{}) (n int, err error) {
+	c.Set()
+	defer c.unset()
+
+	return fmt.Fprint(Output, a...)
+}
+
+// Fprintf formats according to a format specifier and writes to w.
+// It returns the number of bytes written and any write error encountered.
+// On Windows, users should wrap w with colorable.NewColorable() if w is of
+// type *os.File.
+func (c *Color) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
+	c.setWriter(w)
+	defer c.unsetWriter(w)
+
+	return fmt.Fprintf(w, format, a...)
+}
+
+// Printf formats according to a format specifier and writes to standard output.
+// It returns the number of bytes written and any write error encountered.
+// This is the standard fmt.Printf() method wrapped with the given color.
+func (c *Color) Printf(format string, a ...interface{}) (n int, err error) {
+	c.Set()
+	defer c.unset()
+
+	return fmt.Fprintf(Output, format, a...)
+}
+
+// Fprintln formats using the default formats for its operands and writes to w.
+// Spaces are always added between operands and a newline is appended.
+// On Windows, users should wrap w with colorable.NewColorable() if w is of
+// type *os.File.
+func (c *Color) Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
+	c.setWriter(w)
+	defer c.unsetWriter(w)
+
+	return fmt.Fprintln(w, a...)
+}
+
+// Println formats using the default formats for its operands and writes to
+// standard output. Spaces are always added between operands and a newline is
+// appended. It returns the number of bytes written and any write error
+// encountered. This is the standard fmt.Print() method wrapped with the given
+// color.
+func (c *Color) Println(a ...interface{}) (n int, err error) {
+	c.Set()
+	defer c.unset()
+
+	return fmt.Fprintln(Output, a...)
+}
+
+// FprintFunc returns a new function that prints the passed arguments as
+// colorized with color.Fprint().
+func (c *Color) FprintFunc() func(w io.Writer, a ...interface{}) {
+	return func(w io.Writer, a ...interface{}) {
+		c.Fprint(w, a...)
+	}
+}
+
+// PrintFunc returns a new function that prints the passed arguments as
+// colorized with color.Print().
+func (c *Color) PrintFunc() func(a ...interface{}) {
+	return func(a ...interface{}) {
+		c.Print(a...)
+	}
+}
+
+// FprintfFunc returns a new function that prints the passed arguments as
+// colorized with color.Fprintf().
+func (c *Color) FprintfFunc() func(w io.Writer, format string, a ...interface{}) {
+	return func(w io.Writer, format string, a ...interface{}) {
+		c.Fprintf(w, format, a...)
+	}
+}
+
+// PrintfFunc returns a new function that prints the passed arguments as
+// colorized with color.Printf().
+func (c *Color) PrintfFunc() func(format string, a ...interface{}) {
+	return func(format string, a ...interface{}) {
+		c.Printf(format, a...)
+	}
+}
+
+// FprintlnFunc returns a new function that prints the passed arguments as
+// colorized with color.Fprintln().
+func (c *Color) FprintlnFunc() func(w io.Writer, a ...interface{}) {
+	return func(w io.Writer, a ...interface{}) {
+		c.Fprintln(w, a...)
+	}
+}
+
+// PrintlnFunc returns a new function that prints the passed arguments as
+// colorized with color.Println().
+func (c *Color) PrintlnFunc() func(a ...interface{}) {
+	return func(a ...interface{}) {
+		c.Println(a...)
+	}
+}
+
+// SprintFunc returns a new function that returns colorized strings for the
+// given arguments with fmt.Sprint(). Useful to put into or mix into other
+// string. Windows users should use this in conjunction with color.Output, example:
+//
+//	put := New(FgYellow).SprintFunc()
+//	fmt.Fprintf(color.Output, "This is a %s", put("warning"))
+func (c *Color) SprintFunc() func(a ...interface{}) string {
+	return func(a ...interface{}) string {
+		return c.wrap(fmt.Sprint(a...))
+	}
+}
+
+// SprintfFunc returns a new function that returns colorized strings for the
+// given arguments with fmt.Sprintf(). Useful to put into or mix into other
+// string. Windows users should use this in conjunction with color.Output.
+func (c *Color) SprintfFunc() func(format string, a ...interface{}) string {
+	return func(format string, a ...interface{}) string {
+		return c.wrap(fmt.Sprintf(format, a...))
+	}
+}
+
+// SprintlnFunc returns a new function that returns colorized strings for the
+// given arguments with fmt.Sprintln(). Useful to put into or mix into other
+// string. Windows users should use this in conjunction with color.Output.
+func (c *Color) SprintlnFunc() func(a ...interface{}) string {
+	return func(a ...interface{}) string {
+		return c.wrap(fmt.Sprintln(a...))
+	}
+}
+
+// sequence returns a formated SGR sequence to be plugged into a "\x1b[...m"
+// an example output might be: "1;36" -> bold cyan
+func (c *Color) sequence() string {
+	format := make([]string, len(c.params))
+	for i, v := range c.params {
+		format[i] = strconv.Itoa(int(v))
+	}
+
+	return strings.Join(format, ";")
+}
+
+// wrap wraps the s string with the colors attributes. The string is ready to
+// be printed.
+func (c *Color) wrap(s string) string {
+	if c.isNoColorSet() {
+		return s
+	}
+
+	return c.format() + s + c.unformat()
+}
+
+func (c *Color) format() string {
+	return fmt.Sprintf("%s[%sm", escape, c.sequence())
+}
+
+func (c *Color) unformat() string {
+	return fmt.Sprintf("%s[%dm", escape, Reset)
+}
+
+// DisableColor disables the color output. Useful to not change any existing
+// code and still being able to output. Can be used for flags like
+// "--no-color". To enable back use EnableColor() method.
+func (c *Color) DisableColor() {
+	c.noColor = boolPtr(true)
+}
+
+// EnableColor enables the color output. Use it in conjunction with
+// DisableColor(). Otherwise this method has no side effects.
+func (c *Color) EnableColor() {
+	c.noColor = boolPtr(false)
+}
+
+func (c *Color) isNoColorSet() bool {
+	// check first if we have user setted action
+	if c.noColor != nil {
+		return *c.noColor
+	}
+
+	// if not return the global option, which is disabled by default
+	return NoColor
+}
+
+// Equals returns a boolean value indicating whether two colors are equal.
+func (c *Color) Equals(c2 *Color) bool {
+	if len(c.params) != len(c2.params) {
+		return false
+	}
+
+	for _, attr := range c.params {
+		if !c2.attrExists(attr) {
+			return false
+		}
+	}
+
+	return true
+}
+
+func (c *Color) attrExists(a Attribute) bool {
+	for _, attr := range c.params {
+		if attr == a {
+			return true
+		}
+	}
+
+	return false
+}
+
+func boolPtr(v bool) *bool {
+	return &v
+}
+
+func getCachedColor(p Attribute) *Color {
+	colorsCacheMu.Lock()
+	defer colorsCacheMu.Unlock()
+
+	c, ok := colorsCache[p]
+	if !ok {
+		c = New(p)
+		colorsCache[p] = c
+	}
+
+	return c
+}
+
+func colorPrint(format string, p Attribute, a ...interface{}) {
+	c := getCachedColor(p)
+
+	if !strings.HasSuffix(format, "\n") {
+		format += "\n"
+	}
+
+	if len(a) == 0 {
+		c.Print(format)
+	} else {
+		c.Printf(format, a...)
+	}
+}
+
+func colorString(format string, p Attribute, a ...interface{}) string {
+	c := getCachedColor(p)
+
+	if len(a) == 0 {
+		return c.SprintFunc()(format)
+	}
+
+	return c.SprintfFunc()(format, a...)
+}
+
+// Black is an convenient helper function to print with black foreground. A
+// newline is appended to format by default.
+func Black(format string, a ...interface{}) { colorPrint(format, FgBlack, a...) }
+
+// Red is an convenient helper function to print with red foreground. A
+// newline is appended to format by default.
+func Red(format string, a ...interface{}) { colorPrint(format, FgRed, a...) }
+
+// Green is an convenient helper function to print with green foreground. A
+// newline is appended to format by default.
+func Green(format string, a ...interface{}) { colorPrint(format, FgGreen, a...) }
+
+// Yellow is an convenient helper function to print with yellow foreground.
+// A newline is appended to format by default.
+func Yellow(format string, a ...interface{}) { colorPrint(format, FgYellow, a...) }
+
+// Blue is an convenient helper function to print with blue foreground. A
+// newline is appended to format by default.
+func Blue(format string, a ...interface{}) { colorPrint(format, FgBlue, a...) }
+
+// Magenta is an convenient helper function to print with magenta foreground.
+// A newline is appended to format by default.
+func Magenta(format string, a ...interface{}) { colorPrint(format, FgMagenta, a...) }
+
+// Cyan is an convenient helper function to print with cyan foreground. A
+// newline is appended to format by default.
+func Cyan(format string, a ...interface{}) { colorPrint(format, FgCyan, a...) }
+
+// White is an convenient helper function to print with white foreground. A
+// newline is appended to format by default.
+func White(format string, a ...interface{}) { colorPrint(format, FgWhite, a...) }
+
+// BlackString is an convenient helper function to return a string with black
+// foreground.
+func BlackString(format string, a ...interface{}) string { return colorString(format, FgBlack, a...) }
+
+// RedString is an convenient helper function to return a string with red
+// foreground.
+func RedString(format string, a ...interface{}) string { return colorString(format, FgRed, a...) }
+
+// GreenString is an convenient helper function to return a string with green
+// foreground.
+func GreenString(format string, a ...interface{}) string { return colorString(format, FgGreen, a...) }
+
+// YellowString is an convenient helper function to return a string with yellow
+// foreground.
+func YellowString(format string, a ...interface{}) string { return colorString(format, FgYellow, a...) }
+
+// BlueString is an convenient helper function to return a string with blue
+// foreground.
+func BlueString(format string, a ...interface{}) string { return colorString(format, FgBlue, a...) }
+
+// MagentaString is an convenient helper function to return a string with magenta
+// foreground.
+func MagentaString(format string, a ...interface{}) string {
+	return colorString(format, FgMagenta, a...)
+}
+
+// CyanString is an convenient helper function to return a string with cyan
+// foreground.
+func CyanString(format string, a ...interface{}) string { return colorString(format, FgCyan, a...) }
+
+// WhiteString is an convenient helper function to return a string with white
+// foreground.
+func WhiteString(format string, a ...interface{}) string { return colorString(format, FgWhite, a...) }

+ 128 - 0
vendor/github.com/fatih/color/doc.go

@@ -0,0 +1,128 @@
+/*
+Package color is an ANSI color package to output colorized or SGR defined
+output to the standard output. The API can be used in several way, pick one
+that suits you.
+
+Use simple and default helper functions with predefined foreground colors:
+
+    color.Cyan("Prints text in cyan.")
+
+    // a newline will be appended automatically
+    color.Blue("Prints %s in blue.", "text")
+
+    // More default foreground colors..
+    color.Red("We have red")
+    color.Yellow("Yellow color too!")
+    color.Magenta("And many others ..")
+
+However there are times where custom color mixes are required. Below are some
+examples to create custom color objects and use the print functions of each
+separate color object.
+
+    // Create a new color object
+    c := color.New(color.FgCyan).Add(color.Underline)
+    c.Println("Prints cyan text with an underline.")
+
+    // Or just add them to New()
+    d := color.New(color.FgCyan, color.Bold)
+    d.Printf("This prints bold cyan %s\n", "too!.")
+
+
+    // Mix up foreground and background colors, create new mixes!
+    red := color.New(color.FgRed)
+
+    boldRed := red.Add(color.Bold)
+    boldRed.Println("This will print text in bold red.")
+
+    whiteBackground := red.Add(color.BgWhite)
+    whiteBackground.Println("Red text with White background.")
+
+    // Use your own io.Writer output
+    color.New(color.FgBlue).Fprintln(myWriter, "blue color!")
+
+    blue := color.New(color.FgBlue)
+    blue.Fprint(myWriter, "This will print text in blue.")
+
+You can create PrintXxx functions to simplify even more:
+
+    // Create a custom print function for convenient
+    red := color.New(color.FgRed).PrintfFunc()
+    red("warning")
+    red("error: %s", err)
+
+    // Mix up multiple attributes
+    notice := color.New(color.Bold, color.FgGreen).PrintlnFunc()
+    notice("don't forget this...")
+
+You can also FprintXxx functions to pass your own io.Writer:
+
+    blue := color.New(FgBlue).FprintfFunc()
+    blue(myWriter, "important notice: %s", stars)
+
+    // Mix up with multiple attributes
+    success := color.New(color.Bold, color.FgGreen).FprintlnFunc()
+    success(myWriter, don't forget this...")
+
+
+Or create SprintXxx functions to mix strings with other non-colorized strings:
+
+    yellow := New(FgYellow).SprintFunc()
+    red := New(FgRed).SprintFunc()
+
+    fmt.Printf("this is a %s and this is %s.\n", yellow("warning"), red("error"))
+
+    info := New(FgWhite, BgGreen).SprintFunc()
+    fmt.Printf("this %s rocks!\n", info("package"))
+
+Windows support is enabled by default. All Print functions works as intended.
+However only for color.SprintXXX functions, user should use fmt.FprintXXX and
+set the output to color.Output:
+
+    fmt.Fprintf(color.Output, "Windows support: %s", color.GreenString("PASS"))
+
+    info := New(FgWhite, BgGreen).SprintFunc()
+    fmt.Fprintf(color.Output, "this %s rocks!\n", info("package"))
+
+Using with existing code is possible. Just use the Set() method to set the
+standard output to the given parameters. That way a rewrite of an existing
+code is not required.
+
+    // Use handy standard colors.
+    color.Set(color.FgYellow)
+
+    fmt.Println("Existing text will be now in Yellow")
+    fmt.Printf("This one %s\n", "too")
+
+    color.Unset() // don't forget to unset
+
+    // You can mix up parameters
+    color.Set(color.FgMagenta, color.Bold)
+    defer color.Unset() // use it in your function
+
+    fmt.Println("All text will be now bold magenta.")
+
+There might be a case where you want to disable color output (for example to
+pipe the standard output of your app to somewhere else). `Color` has support to
+disable colors both globally and for single color definition. For example
+suppose you have a CLI app and a `--no-color` bool flag. You can easily disable
+the color output with:
+
+    var flagNoColor = flag.Bool("no-color", false, "Disable color output")
+
+    if *flagNoColor {
+    	color.NoColor = true // disables colorized output
+    }
+
+It also has support for single color definitions (local). You can
+disable/enable color output on the fly:
+
+     c := color.New(color.FgCyan)
+     c.Println("Prints cyan text")
+
+     c.DisableColor()
+     c.Println("This is printed without any color")
+
+     c.EnableColor()
+     c.Println("This prints again cyan...")
+*/
+package color

+ 191 - 0
vendor/github.com/go-macaron/binding/LICENSE

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

+ 20 - 0
vendor/github.com/go-macaron/binding/README.md

@@ -0,0 +1,20 @@
+# binding [![Build Status](https://travis-ci.org/go-macaron/binding.svg?branch=master)](https://travis-ci.org/go-macaron/binding) [![](http://gocover.io/_badge/github.com/go-macaron/binding)](http://gocover.io/github.com/go-macaron/binding)
+
+Middleware binding provides request data binding and validation for [Macaron](https://github.com/go-macaron/macaron).
+
+### Installation
+
+	go get github.com/go-macaron/binding
+	
+## Getting Help
+
+- [API Reference](https://gowalker.org/github.com/go-macaron/binding)
+- [Documentation](http://go-macaron.com/docs/middlewares/binding)
+
+## Credits
+
+This package is a modified version of [martini-contrib/binding](https://github.com/martini-contrib/binding).
+
+## License
+
+This project is under the Apache License, Version 2.0. See the [LICENSE](LICENSE) file for the full license text.

+ 669 - 0
vendor/github.com/go-macaron/binding/binding.go

@@ -0,0 +1,669 @@
+// Copyright 2014 Martini Authors
+// Copyright 2014 The Macaron Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+// Package binding is a middleware that provides request data binding and validation for Macaron.
+package binding
+
+import (
+	"encoding/json"
+	"fmt"
+	"io"
+	"mime/multipart"
+	"net/http"
+	"reflect"
+	"regexp"
+	"strconv"
+	"strings"
+	"unicode/utf8"
+
+	"github.com/Unknwon/com"
+	"gopkg.in/macaron.v1"
+)
+
+const _VERSION = "0.3.2"
+
+func Version() string {
+	return _VERSION
+}
+
+func bind(ctx *macaron.Context, obj interface{}, ifacePtr ...interface{}) {
+	contentType := ctx.Req.Header.Get("Content-Type")
+	if ctx.Req.Method == "POST" || ctx.Req.Method == "PUT" || len(contentType) > 0 {
+		switch {
+		case strings.Contains(contentType, "form-urlencoded"):
+			ctx.Invoke(Form(obj, ifacePtr...))
+		case strings.Contains(contentType, "multipart/form-data"):
+			ctx.Invoke(MultipartForm(obj, ifacePtr...))
+		case strings.Contains(contentType, "json"):
+			ctx.Invoke(Json(obj, ifacePtr...))
+		default:
+			var errors Errors
+			if contentType == "" {
+				errors.Add([]string{}, ERR_CONTENT_TYPE, "Empty Content-Type")
+			} else {
+				errors.Add([]string{}, ERR_CONTENT_TYPE, "Unsupported Content-Type")
+			}
+			ctx.Map(errors)
+			ctx.Map(obj) // Map a fake struct so handler won't panic.
+		}
+	} else {
+		ctx.Invoke(Form(obj, ifacePtr...))
+	}
+}
+
+const (
+	_JSON_CONTENT_TYPE          = "application/json; charset=utf-8"
+	STATUS_UNPROCESSABLE_ENTITY = 422
+)
+
+// errorHandler simply counts the number of errors in the
+// context and, if more than 0, writes a response with an
+// error code and a JSON payload describing the errors.
+// The response will have a JSON content-type.
+// Middleware remaining on the stack will not even see the request
+// if, by this point, there are any errors.
+// This is a "default" handler, of sorts, and you are
+// welcome to use your own instead. The Bind middleware
+// invokes this automatically for convenience.
+func errorHandler(errs Errors, rw http.ResponseWriter) {
+	if len(errs) > 0 {
+		rw.Header().Set("Content-Type", _JSON_CONTENT_TYPE)
+		if errs.Has(ERR_DESERIALIZATION) {
+			rw.WriteHeader(http.StatusBadRequest)
+		} else if errs.Has(ERR_CONTENT_TYPE) {
+			rw.WriteHeader(http.StatusUnsupportedMediaType)
+		} else {
+			rw.WriteHeader(STATUS_UNPROCESSABLE_ENTITY)
+		}
+		errOutput, _ := json.Marshal(errs)
+		rw.Write(errOutput)
+		return
+	}
+}
+
+// Bind wraps up the functionality of the Form and Json middleware
+// according to the Content-Type and verb of the request.
+// A Content-Type is required for POST and PUT requests.
+// Bind invokes the ErrorHandler middleware to bail out if errors
+// occurred. If you want to perform your own error handling, use
+// Form or Json middleware directly. An interface pointer can
+// be added as a second argument in order to map the struct to
+// a specific interface.
+func Bind(obj interface{}, ifacePtr ...interface{}) macaron.Handler {
+	return func(ctx *macaron.Context) {
+		bind(ctx, obj, ifacePtr...)
+		if handler, ok := obj.(ErrorHandler); ok {
+			ctx.Invoke(handler.Error)
+		} else {
+			ctx.Invoke(errorHandler)
+		}
+	}
+}
+
+// BindIgnErr will do the exactly same thing as Bind but without any
+// error handling, which user has freedom to deal with them.
+// This allows user take advantages of validation.
+func BindIgnErr(obj interface{}, ifacePtr ...interface{}) macaron.Handler {
+	return func(ctx *macaron.Context) {
+		bind(ctx, obj, ifacePtr...)
+	}
+}
+
+// Form is middleware to deserialize form-urlencoded data from the request.
+// It gets data from the form-urlencoded body, if present, or from the
+// query string. It uses the http.Request.ParseForm() method
+// to perform deserialization, then reflection is used to map each field
+// into the struct with the proper type. Structs with primitive slice types
+// (bool, float, int, string) can support deserialization of repeated form
+// keys, for example: key=val1&key=val2&key=val3
+// An interface pointer can be added as a second argument in order
+// to map the struct to a specific interface.
+func Form(formStruct interface{}, ifacePtr ...interface{}) macaron.Handler {
+	return func(ctx *macaron.Context) {
+		var errors Errors
+
+		ensureNotPointer(formStruct)
+		formStruct := reflect.New(reflect.TypeOf(formStruct))
+		parseErr := ctx.Req.ParseForm()
+
+		// Format validation of the request body or the URL would add considerable overhead,
+		// and ParseForm does not complain when URL encoding is off.
+		// Because an empty request body or url can also mean absence of all needed values,
+		// it is not in all cases a bad request, so let's return 422.
+		if parseErr != nil {
+			errors.Add([]string{}, ERR_DESERIALIZATION, parseErr.Error())
+		}
+		mapForm(formStruct, ctx.Req.Form, nil, errors)
+		validateAndMap(formStruct, ctx, errors, ifacePtr...)
+	}
+}
+
+// Maximum amount of memory to use when parsing a multipart form.
+// Set this to whatever value you prefer; default is 10 MB.
+var MaxMemory = int64(1024 * 1024 * 10)
+
+// MultipartForm works much like Form, except it can parse multipart forms
+// and handle file uploads. Like the other deserialization middleware handlers,
+// you can pass in an interface to make the interface available for injection
+// into other handlers later.
+func MultipartForm(formStruct interface{}, ifacePtr ...interface{}) macaron.Handler {
+	return func(ctx *macaron.Context) {
+		var errors Errors
+		ensureNotPointer(formStruct)
+		formStruct := reflect.New(reflect.TypeOf(formStruct))
+		// This if check is necessary due to https://github.com/martini-contrib/csrf/issues/6
+		if ctx.Req.MultipartForm == nil {
+			// Workaround for multipart forms returning nil instead of an error
+			// when content is not multipart; see https://code.google.com/p/go/issues/detail?id=6334
+			if multipartReader, err := ctx.Req.MultipartReader(); err != nil {
+				errors.Add([]string{}, ERR_DESERIALIZATION, err.Error())
+			} else {
+				form, parseErr := multipartReader.ReadForm(MaxMemory)
+				if parseErr != nil {
+					errors.Add([]string{}, ERR_DESERIALIZATION, parseErr.Error())
+				}
+
+				if ctx.Req.Form == nil {
+					ctx.Req.ParseForm()
+				}
+				for k, v := range form.Value {
+					ctx.Req.Form[k] = append(ctx.Req.Form[k], v...)
+				}
+
+				ctx.Req.MultipartForm = form
+			}
+		}
+		mapForm(formStruct, ctx.Req.MultipartForm.Value, ctx.Req.MultipartForm.File, errors)
+		validateAndMap(formStruct, ctx, errors, ifacePtr...)
+	}
+}
+
+// Json is middleware to deserialize a JSON payload from the request
+// into the struct that is passed in. The resulting struct is then
+// validated, but no error handling is actually performed here.
+// An interface pointer can be added as a second argument in order
+// to map the struct to a specific interface.
+func Json(jsonStruct interface{}, ifacePtr ...interface{}) macaron.Handler {
+	return func(ctx *macaron.Context) {
+		var errors Errors
+		ensureNotPointer(jsonStruct)
+		jsonStruct := reflect.New(reflect.TypeOf(jsonStruct))
+		if ctx.Req.Request.Body != nil {
+			defer ctx.Req.Request.Body.Close()
+			err := json.NewDecoder(ctx.Req.Request.Body).Decode(jsonStruct.Interface())
+			if err != nil && err != io.EOF {
+				errors.Add([]string{}, ERR_DESERIALIZATION, err.Error())
+			}
+		}
+		validateAndMap(jsonStruct, ctx, errors, ifacePtr...)
+	}
+}
+
+// Validate is middleware to enforce required fields. If the struct
+// passed in implements Validator, then the user-defined Validate method
+// is executed, and its errors are mapped to the context. This middleware
+// performs no error handling: it merely detects errors and maps them.
+func Validate(obj interface{}) macaron.Handler {
+	return func(ctx *macaron.Context) {
+		var errors Errors
+		v := reflect.ValueOf(obj)
+		k := v.Kind()
+		if k == reflect.Interface || k == reflect.Ptr {
+			v = v.Elem()
+			k = v.Kind()
+		}
+		if k == reflect.Slice || k == reflect.Array {
+			for i := 0; i < v.Len(); i++ {
+				e := v.Index(i).Interface()
+				errors = validateStruct(errors, e)
+				if validator, ok := e.(Validator); ok {
+					errors = validator.Validate(ctx, errors)
+				}
+			}
+		} else {
+			errors = validateStruct(errors, obj)
+			if validator, ok := obj.(Validator); ok {
+				errors = validator.Validate(ctx, errors)
+			}
+		}
+		ctx.Map(errors)
+	}
+}
+
+var (
+	AlphaDashPattern    = regexp.MustCompile("[^\\d\\w-_]")
+	AlphaDashDotPattern = regexp.MustCompile("[^\\d\\w-_\\.]")
+	EmailPattern        = regexp.MustCompile("[\\w!#$%&'*+/=?^_`{|}~-]+(?:\\.[\\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\\w](?:[\\w-]*[\\w])?\\.)+[a-zA-Z0-9](?:[\\w-]*[\\w])?")
+	URLPattern          = regexp.MustCompile(`(http|https):\/\/(?:\\S+(?::\\S*)?@)?[\w\-_]+(\.[\w\-_]+)*([\w\-\.,@?^=%&amp;:/~\+#]*[\w\-\@?^=%&amp;/~\+#])?`)
+)
+
+type (
+	// Rule represents a validation rule.
+	Rule struct {
+		// IsMatch checks if rule matches.
+		IsMatch func(string) bool
+		// IsValid applies validation rule to condition.
+		IsValid func(Errors, string, interface{}) (bool, Errors)
+	}
+	// RuleMapper represents a validation rule mapper,
+	// it allwos users to add custom validation rules.
+	RuleMapper []*Rule
+)
+
+var ruleMapper RuleMapper
+
+// AddRule adds new validation rule.
+func AddRule(r *Rule) {
+	ruleMapper = append(ruleMapper, r)
+}
+
+func in(fieldValue interface{}, arr string) bool {
+	val := fmt.Sprintf("%v", fieldValue)
+	vals := strings.Split(arr, ",")
+	isIn := false
+	for _, v := range vals {
+		if v == val {
+			isIn = true
+			break
+		}
+	}
+	return isIn
+}
+
+func parseFormName(raw, actual string) string {
+	if len(actual) > 0 {
+		return actual
+	}
+	return nameMapper(raw)
+}
+
+// Performs required field checking on a struct
+func validateStruct(errors Errors, obj interface{}) Errors {
+	typ := reflect.TypeOf(obj)
+	val := reflect.ValueOf(obj)
+
+	if typ.Kind() == reflect.Ptr {
+		typ = typ.Elem()
+		val = val.Elem()
+	}
+
+	for i := 0; i < typ.NumField(); i++ {
+		field := typ.Field(i)
+
+		// Allow ignored fields in the struct
+		if field.Tag.Get("form") == "-" || !val.Field(i).CanInterface() {
+			continue
+		}
+
+		fieldVal := val.Field(i)
+		fieldValue := fieldVal.Interface()
+		zero := reflect.Zero(field.Type).Interface()
+
+		// Validate nested and embedded structs (if pointer, only do so if not nil)
+		if field.Type.Kind() == reflect.Struct ||
+			(field.Type.Kind() == reflect.Ptr && !reflect.DeepEqual(zero, fieldValue) &&
+				field.Type.Elem().Kind() == reflect.Struct) {
+			errors = validateStruct(errors, fieldValue)
+		}
+		errors = validateField(errors, zero, field, fieldVal, fieldValue)
+	}
+	return errors
+}
+
+func validateField(errors Errors, zero interface{}, field reflect.StructField, fieldVal reflect.Value, fieldValue interface{}) Errors {
+	if fieldVal.Kind() == reflect.Slice {
+		for i := 0; i < fieldVal.Len(); i++ {
+			sliceVal := fieldVal.Index(i)
+			if sliceVal.Kind() == reflect.Ptr {
+				sliceVal = sliceVal.Elem()
+			}
+
+			sliceValue := sliceVal.Interface()
+			zero := reflect.Zero(sliceVal.Type()).Interface()
+			if sliceVal.Kind() == reflect.Struct ||
+				(sliceVal.Kind() == reflect.Ptr && !reflect.DeepEqual(zero, sliceValue) &&
+					sliceVal.Elem().Kind() == reflect.Struct) {
+				errors = validateStruct(errors, sliceValue)
+			}
+			/* Apply validation rules to each item in a slice. ISSUE #3
+			else {
+				errors = validateField(errors, zero, field, sliceVal, sliceValue)
+			}*/
+		}
+	}
+
+VALIDATE_RULES:
+	for _, rule := range strings.Split(field.Tag.Get("binding"), ";") {
+		if len(rule) == 0 {
+			continue
+		}
+
+		switch {
+		case rule == "OmitEmpty":
+			if reflect.DeepEqual(zero, fieldValue) {
+				break VALIDATE_RULES
+			}
+		case rule == "Required":
+			if reflect.DeepEqual(zero, fieldValue) {
+				errors.Add([]string{field.Name}, ERR_REQUIRED, "Required")
+				break VALIDATE_RULES
+			}
+		case rule == "AlphaDash":
+			if AlphaDashPattern.MatchString(fmt.Sprintf("%v", fieldValue)) {
+				errors.Add([]string{field.Name}, ERR_ALPHA_DASH, "AlphaDash")
+				break VALIDATE_RULES
+			}
+		case rule == "AlphaDashDot":
+			if AlphaDashDotPattern.MatchString(fmt.Sprintf("%v", fieldValue)) {
+				errors.Add([]string{field.Name}, ERR_ALPHA_DASH_DOT, "AlphaDashDot")
+				break VALIDATE_RULES
+			}
+		case strings.HasPrefix(rule, "Size("):
+			size, _ := strconv.Atoi(rule[5 : len(rule)-1])
+			if str, ok := fieldValue.(string); ok && utf8.RuneCountInString(str) != size {
+				errors.Add([]string{field.Name}, ERR_SIZE, "Size")
+				break VALIDATE_RULES
+			}
+			v := reflect.ValueOf(fieldValue)
+			if v.Kind() == reflect.Slice && v.Len() != size {
+				errors.Add([]string{field.Name}, ERR_SIZE, "Size")
+				break VALIDATE_RULES
+			}
+		case strings.HasPrefix(rule, "MinSize("):
+			min, _ := strconv.Atoi(rule[8 : len(rule)-1])
+			if str, ok := fieldValue.(string); ok && utf8.RuneCountInString(str) < min {
+				errors.Add([]string{field.Name}, ERR_MIN_SIZE, "MinSize")
+				break VALIDATE_RULES
+			}
+			v := reflect.ValueOf(fieldValue)
+			if v.Kind() == reflect.Slice && v.Len() < min {
+				errors.Add([]string{field.Name}, ERR_MIN_SIZE, "MinSize")
+				break VALIDATE_RULES
+			}
+		case strings.HasPrefix(rule, "MaxSize("):
+			max, _ := strconv.Atoi(rule[8 : len(rule)-1])
+			if str, ok := fieldValue.(string); ok && utf8.RuneCountInString(str) > max {
+				errors.Add([]string{field.Name}, ERR_MAX_SIZE, "MaxSize")
+				break VALIDATE_RULES
+			}
+			v := reflect.ValueOf(fieldValue)
+			if v.Kind() == reflect.Slice && v.Len() > max {
+				errors.Add([]string{field.Name}, ERR_MAX_SIZE, "MaxSize")
+				break VALIDATE_RULES
+			}
+		case strings.HasPrefix(rule, "Range("):
+			nums := strings.Split(rule[6:len(rule)-1], ",")
+			if len(nums) != 2 {
+				break VALIDATE_RULES
+			}
+			val := com.StrTo(fmt.Sprintf("%v", fieldValue)).MustInt()
+			if val < com.StrTo(nums[0]).MustInt() || val > com.StrTo(nums[1]).MustInt() {
+				errors.Add([]string{field.Name}, ERR_RANGE, "Range")
+				break VALIDATE_RULES
+			}
+		case rule == "Email":
+			if !EmailPattern.MatchString(fmt.Sprintf("%v", fieldValue)) {
+				errors.Add([]string{field.Name}, ERR_EMAIL, "Email")
+				break VALIDATE_RULES
+			}
+		case rule == "Url":
+			str := fmt.Sprintf("%v", fieldValue)
+			if len(str) == 0 {
+				continue
+			} else if !URLPattern.MatchString(str) {
+				errors.Add([]string{field.Name}, ERR_URL, "Url")
+				break VALIDATE_RULES
+			}
+		case strings.HasPrefix(rule, "In("):
+			if !in(fieldValue, rule[3:len(rule)-1]) {
+				errors.Add([]string{field.Name}, ERR_IN, "In")
+				break VALIDATE_RULES
+			}
+		case strings.HasPrefix(rule, "NotIn("):
+			if in(fieldValue, rule[6:len(rule)-1]) {
+				errors.Add([]string{field.Name}, ERR_NOT_INT, "NotIn")
+				break VALIDATE_RULES
+			}
+		case strings.HasPrefix(rule, "Include("):
+			if !strings.Contains(fmt.Sprintf("%v", fieldValue), rule[8:len(rule)-1]) {
+				errors.Add([]string{field.Name}, ERR_INCLUDE, "Include")
+				break VALIDATE_RULES
+			}
+		case strings.HasPrefix(rule, "Exclude("):
+			if strings.Contains(fmt.Sprintf("%v", fieldValue), rule[8:len(rule)-1]) {
+				errors.Add([]string{field.Name}, ERR_EXCLUDE, "Exclude")
+				break VALIDATE_RULES
+			}
+		case strings.HasPrefix(rule, "Default("):
+			if reflect.DeepEqual(zero, fieldValue) {
+				if fieldVal.CanAddr() {
+					setWithProperType(field.Type.Kind(), rule[8:len(rule)-1], fieldVal, field.Tag.Get("form"), errors)
+				} else {
+					errors.Add([]string{field.Name}, ERR_EXCLUDE, "Default")
+					break VALIDATE_RULES
+				}
+			}
+		default:
+			// Apply custom validation rules.
+			var isValid bool
+			for i := range ruleMapper {
+				if ruleMapper[i].IsMatch(rule) {
+					isValid, errors = ruleMapper[i].IsValid(errors, field.Name, fieldValue)
+					if !isValid {
+						break VALIDATE_RULES
+					}
+				}
+			}
+		}
+	}
+	return errors
+}
+
+// NameMapper represents a form tag name mapper.
+type NameMapper func(string) string
+
+var (
+	nameMapper = func(field string) string {
+		newstr := make([]rune, 0, len(field))
+		for i, chr := range field {
+			if isUpper := 'A' <= chr && chr <= 'Z'; isUpper {
+				if i > 0 {
+					newstr = append(newstr, '_')
+				}
+				chr -= ('A' - 'a')
+			}
+			newstr = append(newstr, chr)
+		}
+		return string(newstr)
+	}
+)
+
+// SetNameMapper sets name mapper.
+func SetNameMapper(nm NameMapper) {
+	nameMapper = nm
+}
+
+// Takes values from the form data and puts them into a struct
+func mapForm(formStruct reflect.Value, form map[string][]string,
+	formfile map[string][]*multipart.FileHeader, errors Errors) {
+
+	if formStruct.Kind() == reflect.Ptr {
+		formStruct = formStruct.Elem()
+	}
+	typ := formStruct.Type()
+
+	for i := 0; i < typ.NumField(); i++ {
+		typeField := typ.Field(i)
+		structField := formStruct.Field(i)
+
+		if typeField.Type.Kind() == reflect.Ptr && typeField.Anonymous {
+			structField.Set(reflect.New(typeField.Type.Elem()))
+			mapForm(structField.Elem(), form, formfile, errors)
+			if reflect.DeepEqual(structField.Elem().Interface(), reflect.Zero(structField.Elem().Type()).Interface()) {
+				structField.Set(reflect.Zero(structField.Type()))
+			}
+		} else if typeField.Type.Kind() == reflect.Struct {
+			mapForm(structField, form, formfile, errors)
+		}
+
+		inputFieldName := parseFormName(typeField.Name, typeField.Tag.Get("form"))
+		if len(inputFieldName) == 0 || !structField.CanSet() {
+			continue
+		}
+
+		inputValue, exists := form[inputFieldName]
+		if exists {
+			numElems := len(inputValue)
+			if structField.Kind() == reflect.Slice && numElems > 0 {
+				sliceOf := structField.Type().Elem().Kind()
+				slice := reflect.MakeSlice(structField.Type(), numElems, numElems)
+				for i := 0; i < numElems; i++ {
+					setWithProperType(sliceOf, inputValue[i], slice.Index(i), inputFieldName, errors)
+				}
+				formStruct.Field(i).Set(slice)
+			} else {
+				setWithProperType(typeField.Type.Kind(), inputValue[0], structField, inputFieldName, errors)
+			}
+			continue
+		}
+
+		inputFile, exists := formfile[inputFieldName]
+		if !exists {
+			continue
+		}
+		fhType := reflect.TypeOf((*multipart.FileHeader)(nil))
+		numElems := len(inputFile)
+		if structField.Kind() == reflect.Slice && numElems > 0 && structField.Type().Elem() == fhType {
+			slice := reflect.MakeSlice(structField.Type(), numElems, numElems)
+			for i := 0; i < numElems; i++ {
+				slice.Index(i).Set(reflect.ValueOf(inputFile[i]))
+			}
+			structField.Set(slice)
+		} else if structField.Type() == fhType {
+			structField.Set(reflect.ValueOf(inputFile[0]))
+		}
+	}
+}
+
+// This sets the value in a struct of an indeterminate type to the
+// matching value from the request (via Form middleware) in the
+// same type, so that not all deserialized values have to be strings.
+// Supported types are string, int, float, and bool.
+func setWithProperType(valueKind reflect.Kind, val string, structField reflect.Value, nameInTag string, errors Errors) {
+	switch valueKind {
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		if val == "" {
+			val = "0"
+		}
+		intVal, err := strconv.ParseInt(val, 10, 64)
+		if err != nil {
+			errors.Add([]string{nameInTag}, ERR_INTERGER_TYPE, "Value could not be parsed as integer")
+		} else {
+			structField.SetInt(intVal)
+		}
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+		if val == "" {
+			val = "0"
+		}
+		uintVal, err := strconv.ParseUint(val, 10, 64)
+		if err != nil {
+			errors.Add([]string{nameInTag}, ERR_INTERGER_TYPE, "Value could not be parsed as unsigned integer")
+		} else {
+			structField.SetUint(uintVal)
+		}
+	case reflect.Bool:
+		if val == "on" {
+			structField.SetBool(true)
+			return
+		}
+
+		if val == "" {
+			val = "false"
+		}
+		boolVal, err := strconv.ParseBool(val)
+		if err != nil {
+			errors.Add([]string{nameInTag}, ERR_BOOLEAN_TYPE, "Value could not be parsed as boolean")
+		} else if boolVal {
+			structField.SetBool(true)
+		}
+	case reflect.Float32:
+		if val == "" {
+			val = "0.0"
+		}
+		floatVal, err := strconv.ParseFloat(val, 32)
+		if err != nil {
+			errors.Add([]string{nameInTag}, ERR_FLOAT_TYPE, "Value could not be parsed as 32-bit float")
+		} else {
+			structField.SetFloat(floatVal)
+		}
+	case reflect.Float64:
+		if val == "" {
+			val = "0.0"
+		}
+		floatVal, err := strconv.ParseFloat(val, 64)
+		if err != nil {
+			errors.Add([]string{nameInTag}, ERR_FLOAT_TYPE, "Value could not be parsed as 64-bit float")
+		} else {
+			structField.SetFloat(floatVal)
+		}
+	case reflect.String:
+		structField.SetString(val)
+	}
+}
+
+// Don't pass in pointers to bind to. Can lead to bugs.
+func ensureNotPointer(obj interface{}) {
+	if reflect.TypeOf(obj).Kind() == reflect.Ptr {
+		panic("Pointers are not accepted as binding models")
+	}
+}
+
+// Performs validation and combines errors from validation
+// with errors from deserialization, then maps both the
+// resulting struct and the errors to the context.
+func validateAndMap(obj reflect.Value, ctx *macaron.Context, errors Errors, ifacePtr ...interface{}) {
+	ctx.Invoke(Validate(obj.Interface()))
+	errors = append(errors, getErrors(ctx)...)
+	ctx.Map(errors)
+	ctx.Map(obj.Elem().Interface())
+	if len(ifacePtr) > 0 {
+		ctx.MapTo(obj.Elem().Interface(), ifacePtr[0])
+	}
+}
+
+// getErrors simply gets the errors from the context (it's kind of a chore)
+func getErrors(ctx *macaron.Context) Errors {
+	return ctx.GetVal(reflect.TypeOf(Errors{})).Interface().(Errors)
+}
+
+type (
+	// ErrorHandler is the interface that has custom error handling process.
+	ErrorHandler interface {
+		// Error handles validation errors with custom process.
+		Error(*macaron.Context, Errors)
+	}
+
+	// Validator is the interface that handles some rudimentary
+	// request validation logic so your application doesn't have to.
+	Validator interface {
+		// Validate validates that the request is OK. It is recommended
+		// that validation be limited to checking values for syntax and
+		// semantics, enough to know that you can make sense of the request
+		// in your application. For example, you might verify that a credit
+		// card number matches a valid pattern, but you probably wouldn't
+		// perform an actual credit card authorization here.
+		Validate(*macaron.Context, Errors) Errors
+	}
+)

+ 159 - 0
vendor/github.com/go-macaron/binding/errors.go

@@ -0,0 +1,159 @@
+// Copyright 2014 Martini Authors
+// Copyright 2014 The Macaron Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package binding
+
+const (
+	// Type mismatch errors.
+	ERR_CONTENT_TYPE    = "ContentTypeError"
+	ERR_DESERIALIZATION = "DeserializationError"
+	ERR_INTERGER_TYPE   = "IntegerTypeError"
+	ERR_BOOLEAN_TYPE    = "BooleanTypeError"
+	ERR_FLOAT_TYPE      = "FloatTypeError"
+
+	// Validation errors.
+	ERR_REQUIRED       = "RequiredError"
+	ERR_ALPHA_DASH     = "AlphaDashError"
+	ERR_ALPHA_DASH_DOT = "AlphaDashDotError"
+	ERR_SIZE           = "SizeError"
+	ERR_MIN_SIZE       = "MinSizeError"
+	ERR_MAX_SIZE       = "MaxSizeError"
+	ERR_RANGE          = "RangeError"
+	ERR_EMAIL          = "EmailError"
+	ERR_URL            = "UrlError"
+	ERR_IN             = "InError"
+	ERR_NOT_INT        = "NotInError"
+	ERR_INCLUDE        = "IncludeError"
+	ERR_EXCLUDE        = "ExcludeError"
+	ERR_DEFAULT        = "DefaultError"
+)
+
+type (
+	// Errors may be generated during deserialization, binding,
+	// or validation. This type is mapped to the context so you
+	// can inject it into your own handlers and use it in your
+	// application if you want all your errors to look the same.
+	Errors []Error
+
+	Error struct {
+		// An error supports zero or more field names, because an
+		// error can morph three ways: (1) it can indicate something
+		// wrong with the request as a whole, (2) it can point to a
+		// specific problem with a particular input field, or (3) it
+		// can span multiple related input fields.
+		FieldNames []string `json:"fieldNames,omitempty"`
+
+		// The classification is like an error code, convenient to
+		// use when processing or categorizing an error programmatically.
+		// It may also be called the "kind" of error.
+		Classification string `json:"classification,omitempty"`
+
+		// Message should be human-readable and detailed enough to
+		// pinpoint and resolve the problem, but it should be brief. For
+		// example, a payload of 100 objects in a JSON array might have
+		// an error in the 41st object. The message should help the
+		// end user find and fix the error with their request.
+		Message string `json:"message,omitempty"`
+	}
+)
+
+// Add adds an error associated with the fields indicated
+// by fieldNames, with the given classification and message.
+func (e *Errors) Add(fieldNames []string, classification, message string) {
+	*e = append(*e, Error{
+		FieldNames:     fieldNames,
+		Classification: classification,
+		Message:        message,
+	})
+}
+
+// Len returns the number of errors.
+func (e *Errors) Len() int {
+	return len(*e)
+}
+
+// Has determines whether an Errors slice has an Error with
+// a given classification in it; it does not search on messages
+// or field names.
+func (e *Errors) Has(class string) bool {
+	for _, err := range *e {
+		if err.Kind() == class {
+			return true
+		}
+	}
+	return false
+}
+
+/*
+// WithClass gets a copy of errors that are classified by the
+// the given classification.
+func (e *Errors) WithClass(classification string) Errors {
+	var errs Errors
+	for _, err := range *e {
+		if err.Kind() == classification {
+			errs = append(errs, err)
+		}
+	}
+	return errs
+}
+
+// ForField gets a copy of errors that are associated with the
+// field by the given name.
+func (e *Errors) ForField(name string) Errors {
+	var errs Errors
+	for _, err := range *e {
+		for _, fieldName := range err.Fields() {
+			if fieldName == name {
+				errs = append(errs, err)
+				break
+			}
+		}
+	}
+	return errs
+}
+
+// Get gets errors of a particular class for the specified
+// field name.
+func (e *Errors) Get(class, fieldName string) Errors {
+	var errs Errors
+	for _, err := range *e {
+		if err.Kind() == class {
+			for _, nameOfField := range err.Fields() {
+				if nameOfField == fieldName {
+					errs = append(errs, err)
+					break
+				}
+			}
+		}
+	}
+	return errs
+}
+*/
+
+// Fields returns the list of field names this error is
+// associated with.
+func (e Error) Fields() []string {
+	return e.FieldNames
+}
+
+// Kind returns this error's classification.
+func (e Error) Kind() string {
+	return e.Classification
+}
+
+// Error returns this error's message.
+func (e Error) Error() string {
+	return e.Message
+}

+ 191 - 0
vendor/github.com/go-macaron/cache/LICENSE

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

+ 20 - 0
vendor/github.com/go-macaron/cache/README.md

@@ -0,0 +1,20 @@
+# cache [![Build Status](https://travis-ci.org/go-macaron/cache.svg?branch=master)](https://travis-ci.org/go-macaron/cache) [![](http://gocover.io/_badge/github.com/go-macaron/cache)](http://gocover.io/github.com/go-macaron/cache)
+
+Middleware cache provides cache management for [Macaron](https://github.com/go-macaron/macaron). It can use many cache adapters, including memory, file, Redis, Memcache, PostgreSQL, MySQL, Ledis and Nodb.
+
+### Installation
+
+	go get github.com/go-macaron/cache
+
+## Getting Help
+
+- [API Reference](https://gowalker.org/github.com/go-macaron/cache)
+- [Documentation](http://go-macaron.com/docs/middlewares/cache)
+
+## Credits
+
+This package is a modified version of [beego/cache](https://github.com/astaxie/beego/tree/master/cache).
+
+## License
+
+This project is under the Apache License, Version 2.0. See the [LICENSE](LICENSE) file for the full license text.

+ 122 - 0
vendor/github.com/go-macaron/cache/cache.go

@@ -0,0 +1,122 @@
+// Copyright 2013 Beego Authors
+// Copyright 2014 The Macaron Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+// Package cache is a middleware that provides the cache management of Macaron.
+package cache
+
+import (
+	"fmt"
+
+	"gopkg.in/macaron.v1"
+)
+
+const _VERSION = "0.3.0"
+
+func Version() string {
+	return _VERSION
+}
+
+// Cache is the interface that operates the cache data.
+type Cache interface {
+	// Put puts value into cache with key and expire time.
+	Put(key string, val interface{}, timeout int64) error
+	// Get gets cached value by given key.
+	Get(key string) interface{}
+	// Delete deletes cached value by given key.
+	Delete(key string) error
+	// Incr increases cached int-type value by given key as a counter.
+	Incr(key string) error
+	// Decr decreases cached int-type value by given key as a counter.
+	Decr(key string) error
+	// IsExist returns true if cached value exists.
+	IsExist(key string) bool
+	// Flush deletes all cached data.
+	Flush() error
+	// StartAndGC starts GC routine based on config string settings.
+	StartAndGC(opt Options) error
+}
+
+// Options represents a struct for specifying configuration options for the cache middleware.
+type Options struct {
+	// Name of adapter. Default is "memory".
+	Adapter string
+	// Adapter configuration, it's corresponding to adapter.
+	AdapterConfig string
+	// GC interval time in seconds. Default is 60.
+	Interval int
+	// Occupy entire database. Default is false.
+	OccupyMode bool
+	// Configuration section name. Default is "cache".
+	Section string
+}
+
+func prepareOptions(options []Options) Options {
+	var opt Options
+	if len(options) > 0 {
+		opt = options[0]
+	}
+	if len(opt.Section) == 0 {
+		opt.Section = "cache"
+	}
+	sec := macaron.Config().Section(opt.Section)
+
+	if len(opt.Adapter) == 0 {
+		opt.Adapter = sec.Key("ADAPTER").MustString("memory")
+	}
+	if opt.Interval == 0 {
+		opt.Interval = sec.Key("INTERVAL").MustInt(60)
+	}
+	if len(opt.AdapterConfig) == 0 {
+		opt.AdapterConfig = sec.Key("ADAPTER_CONFIG").MustString("data/caches")
+	}
+
+	return opt
+}
+
+// NewCacher creates and returns a new cacher by given adapter name and configuration.
+// It panics when given adapter isn't registered and starts GC automatically.
+func NewCacher(name string, opt Options) (Cache, error) {
+	adapter, ok := adapters[name]
+	if !ok {
+		return nil, fmt.Errorf("cache: unknown adapter '%s'(forgot to import?)", name)
+	}
+	return adapter, adapter.StartAndGC(opt)
+}
+
+// Cacher is a middleware that maps a cache.Cache service into the Macaron handler chain.
+// An single variadic cache.Options struct can be optionally provided to configure.
+func Cacher(options ...Options) macaron.Handler {
+	opt := prepareOptions(options)
+	cache, err := NewCacher(opt.Adapter, opt)
+	if err != nil {
+		panic(err)
+	}
+	return func(ctx *macaron.Context) {
+		ctx.Map(cache)
+	}
+}
+
+var adapters = make(map[string]Cache)
+
+// Register registers a adapter.
+func Register(name string, adapter Cache) {
+	if adapter == nil {
+		panic("cache: cannot register adapter with nil value")
+	}
+	if _, dup := adapters[name]; dup {
+		panic(fmt.Errorf("cache: cannot register adapter '%s' twice", name))
+	}
+	adapters[name] = adapter
+}

+ 208 - 0
vendor/github.com/go-macaron/cache/file.go

@@ -0,0 +1,208 @@
+// Copyright 2013 Beego Authors
+// Copyright 2014 The Macaron Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package cache
+
+import (
+	"crypto/md5"
+	"encoding/hex"
+	"fmt"
+	"io/ioutil"
+	"log"
+	"os"
+	"path/filepath"
+	"sync"
+	"time"
+
+	"github.com/Unknwon/com"
+	"gopkg.in/macaron.v1"
+)
+
+// Item represents a cache item.
+type Item struct {
+	Val     interface{}
+	Created int64
+	Expire  int64
+}
+
+func (item *Item) hasExpired() bool {
+	return item.Expire > 0 &&
+		(time.Now().Unix()-item.Created) >= item.Expire
+}
+
+// FileCacher represents a file cache adapter implementation.
+type FileCacher struct {
+	lock     sync.Mutex
+	rootPath string
+	interval int // GC interval.
+}
+
+// NewFileCacher creates and returns a new file cacher.
+func NewFileCacher() *FileCacher {
+	return &FileCacher{}
+}
+
+func (c *FileCacher) filepath(key string) string {
+	m := md5.Sum([]byte(key))
+	hash := hex.EncodeToString(m[:])
+	return filepath.Join(c.rootPath, string(hash[0]), string(hash[1]), hash)
+}
+
+// Put puts value into cache with key and expire time.
+// If expired is 0, it will not be deleted by GC.
+func (c *FileCacher) Put(key string, val interface{}, expire int64) error {
+	filename := c.filepath(key)
+	item := &Item{val, time.Now().Unix(), expire}
+	data, err := EncodeGob(item)
+	if err != nil {
+		return err
+	}
+
+	os.MkdirAll(filepath.Dir(filename), os.ModePerm)
+	return ioutil.WriteFile(filename, data, os.ModePerm)
+}
+
+func (c *FileCacher) read(key string) (*Item, error) {
+	filename := c.filepath(key)
+
+	data, err := ioutil.ReadFile(filename)
+	if err != nil {
+		return nil, err
+	}
+
+	item := new(Item)
+	return item, DecodeGob(data, item)
+}
+
+// Get gets cached value by given key.
+func (c *FileCacher) Get(key string) interface{} {
+	item, err := c.read(key)
+	if err != nil {
+		return nil
+	}
+
+	if item.hasExpired() {
+		os.Remove(c.filepath(key))
+		return nil
+	}
+	return item.Val
+}
+
+// Delete deletes cached value by given key.
+func (c *FileCacher) Delete(key string) error {
+	return os.Remove(c.filepath(key))
+}
+
+// Incr increases cached int-type value by given key as a counter.
+func (c *FileCacher) Incr(key string) error {
+	item, err := c.read(key)
+	if err != nil {
+		return err
+	}
+
+	item.Val, err = Incr(item.Val)
+	if err != nil {
+		return err
+	}
+
+	return c.Put(key, item.Val, item.Expire)
+}
+
+// Decrease cached int value.
+func (c *FileCacher) Decr(key string) error {
+	item, err := c.read(key)
+	if err != nil {
+		return err
+	}
+
+	item.Val, err = Decr(item.Val)
+	if err != nil {
+		return err
+	}
+
+	return c.Put(key, item.Val, item.Expire)
+}
+
+// IsExist returns true if cached value exists.
+func (c *FileCacher) IsExist(key string) bool {
+	return com.IsExist(c.filepath(key))
+}
+
+// Flush deletes all cached data.
+func (c *FileCacher) Flush() error {
+	return os.RemoveAll(c.rootPath)
+}
+
+func (c *FileCacher) startGC() {
+	c.lock.Lock()
+	defer c.lock.Unlock()
+
+	if c.interval < 1 {
+		return
+	}
+
+	if err := filepath.Walk(c.rootPath, func(path string, fi os.FileInfo, err error) error {
+		if err != nil {
+			return fmt.Errorf("Walk: %v", err)
+		}
+
+		if fi.IsDir() {
+			return nil
+		}
+
+		data, err := ioutil.ReadFile(path)
+		if err != nil && !os.IsNotExist(err) {
+			fmt.Errorf("ReadFile: %v", err)
+		}
+
+		item := new(Item)
+		if err = DecodeGob(data, item); err != nil {
+			return err
+		}
+		if item.hasExpired() {
+			if err = os.Remove(path); err != nil && !os.IsNotExist(err) {
+				return fmt.Errorf("Remove: %v", err)
+			}
+		}
+		return nil
+	}); err != nil {
+		log.Printf("error garbage collecting cache files: %v", err)
+	}
+
+	time.AfterFunc(time.Duration(c.interval)*time.Second, func() { c.startGC() })
+}
+
+// StartAndGC starts GC routine based on config string settings.
+func (c *FileCacher) StartAndGC(opt Options) error {
+	c.lock.Lock()
+	c.rootPath = opt.AdapterConfig
+	c.interval = opt.Interval
+
+	if !filepath.IsAbs(c.rootPath) {
+		c.rootPath = filepath.Join(macaron.Root, c.rootPath)
+	}
+	c.lock.Unlock()
+
+	if err := os.MkdirAll(c.rootPath, os.ModePerm); err != nil {
+		return err
+	}
+
+	go c.startGC()
+	return nil
+}
+
+func init() {
+	Register("file", NewFileCacher())
+}

+ 92 - 0
vendor/github.com/go-macaron/cache/memcache/memcache.go

@@ -0,0 +1,92 @@
+// Copyright 2013 Beego Authors
+// Copyright 2014 The Macaron Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package cache
+
+import (
+	"strings"
+
+	"github.com/Unknwon/com"
+	"github.com/bradfitz/gomemcache/memcache"
+
+	"github.com/go-macaron/cache"
+)
+
+// MemcacheCacher represents a memcache cache adapter implementation.
+type MemcacheCacher struct {
+	c *memcache.Client
+}
+
+func NewItem(key string, data []byte, expire int32) *memcache.Item {
+	return &memcache.Item{
+		Key:        key,
+		Value:      data,
+		Expiration: expire,
+	}
+}
+
+// Put puts value into cache with key and expire time.
+// If expired is 0, it lives forever.
+func (c *MemcacheCacher) Put(key string, val interface{}, expire int64) error {
+	return c.c.Set(NewItem(key, []byte(com.ToStr(val)), int32(expire)))
+}
+
+// Get gets cached value by given key.
+func (c *MemcacheCacher) Get(key string) interface{} {
+	item, err := c.c.Get(key)
+	if err != nil {
+		return nil
+	}
+	return string(item.Value)
+}
+
+// Delete deletes cached value by given key.
+func (c *MemcacheCacher) Delete(key string) error {
+	return c.c.Delete(key)
+}
+
+// Incr increases cached int-type value by given key as a counter.
+func (c *MemcacheCacher) Incr(key string) error {
+	_, err := c.c.Increment(key, 1)
+	return err
+}
+
+// Decr decreases cached int-type value by given key as a counter.
+func (c *MemcacheCacher) Decr(key string) error {
+	_, err := c.c.Decrement(key, 1)
+	return err
+}
+
+// IsExist returns true if cached value exists.
+func (c *MemcacheCacher) IsExist(key string) bool {
+	_, err := c.c.Get(key)
+	return err == nil
+}
+
+// Flush deletes all cached data.
+func (c *MemcacheCacher) Flush() error {
+	return c.c.FlushAll()
+}
+
+// StartAndGC starts GC routine based on config string settings.
+// AdapterConfig: 127.0.0.1:9090;127.0.0.1:9091
+func (c *MemcacheCacher) StartAndGC(opt cache.Options) error {
+	c.c = memcache.New(strings.Split(opt.AdapterConfig, ";")...)
+	return nil
+}
+
+func init() {
+	cache.Register("memcache", &MemcacheCacher{})
+}

+ 1 - 0
vendor/github.com/go-macaron/cache/memcache/memcache.goconvey

@@ -0,0 +1 @@
+ignore

+ 179 - 0
vendor/github.com/go-macaron/cache/memory.go

@@ -0,0 +1,179 @@
+// Copyright 2013 Beego Authors
+// Copyright 2014 The Macaron Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package cache
+
+import (
+	"errors"
+	"sync"
+	"time"
+)
+
+// MemoryItem represents a memory cache item.
+type MemoryItem struct {
+	val     interface{}
+	created int64
+	expire  int64
+}
+
+func (item *MemoryItem) hasExpired() bool {
+	return item.expire > 0 &&
+		(time.Now().Unix()-item.created) >= item.expire
+}
+
+// MemoryCacher represents a memory cache adapter implementation.
+type MemoryCacher struct {
+	lock     sync.RWMutex
+	items    map[string]*MemoryItem
+	interval int // GC interval.
+}
+
+// NewMemoryCacher creates and returns a new memory cacher.
+func NewMemoryCacher() *MemoryCacher {
+	return &MemoryCacher{items: make(map[string]*MemoryItem)}
+}
+
+// Put puts value into cache with key and expire time.
+// If expired is 0, it will be deleted by next GC operation.
+func (c *MemoryCacher) Put(key string, val interface{}, expire int64) error {
+	c.lock.Lock()
+	defer c.lock.Unlock()
+
+	c.items[key] = &MemoryItem{
+		val:     val,
+		created: time.Now().Unix(),
+		expire:  expire,
+	}
+	return nil
+}
+
+// Get gets cached value by given key.
+func (c *MemoryCacher) Get(key string) interface{} {
+	c.lock.RLock()
+	defer c.lock.RUnlock()
+
+	item, ok := c.items[key]
+	if !ok {
+		return nil
+	}
+	if item.hasExpired() {
+		go c.Delete(key)
+		return nil
+	}
+	return item.val
+}
+
+// Delete deletes cached value by given key.
+func (c *MemoryCacher) Delete(key string) error {
+	c.lock.Lock()
+	defer c.lock.Unlock()
+
+	delete(c.items, key)
+	return nil
+}
+
+// Incr increases cached int-type value by given key as a counter.
+func (c *MemoryCacher) Incr(key string) (err error) {
+	c.lock.RLock()
+	defer c.lock.RUnlock()
+
+	item, ok := c.items[key]
+	if !ok {
+		return errors.New("key not exist")
+	}
+	item.val, err = Incr(item.val)
+	return err
+}
+
+// Decr decreases cached int-type value by given key as a counter.
+func (c *MemoryCacher) Decr(key string) (err error) {
+	c.lock.RLock()
+	defer c.lock.RUnlock()
+
+	item, ok := c.items[key]
+	if !ok {
+		return errors.New("key not exist")
+	}
+
+	item.val, err = Decr(item.val)
+	return err
+}
+
+// IsExist returns true if cached value exists.
+func (c *MemoryCacher) IsExist(key string) bool {
+	c.lock.RLock()
+	defer c.lock.RUnlock()
+
+	_, ok := c.items[key]
+	return ok
+}
+
+// Flush deletes all cached data.
+func (c *MemoryCacher) Flush() error {
+	c.lock.Lock()
+	defer c.lock.Unlock()
+
+	c.items = make(map[string]*MemoryItem)
+	return nil
+}
+
+func (c *MemoryCacher) checkRawExpiration(key string) {
+	item, ok := c.items[key]
+	if !ok {
+		return
+	}
+
+	if item.hasExpired() {
+		delete(c.items, key)
+	}
+}
+
+func (c *MemoryCacher) checkExpiration(key string) {
+	c.lock.Lock()
+	defer c.lock.Unlock()
+
+	c.checkRawExpiration(key)
+}
+
+func (c *MemoryCacher) startGC() {
+	c.lock.Lock()
+	defer c.lock.Unlock()
+
+	if c.interval < 1 {
+		return
+	}
+
+	if c.items != nil {
+		for key, _ := range c.items {
+			c.checkRawExpiration(key)
+		}
+	}
+
+	time.AfterFunc(time.Duration(c.interval)*time.Second, func() { c.startGC() })
+}
+
+// StartAndGC starts GC routine based on config string settings.
+func (c *MemoryCacher) StartAndGC(opt Options) error {
+	c.lock.Lock()
+	c.interval = opt.Interval
+	c.lock.Unlock()
+
+	go c.startGC()
+	return nil
+}
+
+func init() {
+	Register("memory", NewMemoryCacher())
+}

+ 178 - 0
vendor/github.com/go-macaron/cache/redis/redis.go

@@ -0,0 +1,178 @@
+// Copyright 2013 Beego Authors
+// Copyright 2014 The Macaron Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package cache
+
+import (
+	"fmt"
+	"strings"
+	"time"
+
+	"github.com/Unknwon/com"
+	"gopkg.in/ini.v1"
+	"gopkg.in/redis.v2"
+
+	"github.com/go-macaron/cache"
+)
+
+// RedisCacher represents a redis cache adapter implementation.
+type RedisCacher struct {
+	c          *redis.Client
+	prefix     string
+	hsetName   string
+	occupyMode bool
+}
+
+// Put puts value into cache with key and expire time.
+// If expired is 0, it lives forever.
+func (c *RedisCacher) Put(key string, val interface{}, expire int64) error {
+	key = c.prefix + key
+	if expire == 0 {
+		if err := c.c.Set(key, com.ToStr(val)).Err(); err != nil {
+			return err
+		}
+	} else {
+		dur, err := time.ParseDuration(com.ToStr(expire) + "s")
+		if err != nil {
+			return err
+		}
+		if err = c.c.SetEx(key, dur, com.ToStr(val)).Err(); err != nil {
+			return err
+		}
+	}
+
+	if c.occupyMode {
+		return nil
+	}
+	return c.c.HSet(c.hsetName, key, "0").Err()
+}
+
+// Get gets cached value by given key.
+func (c *RedisCacher) Get(key string) interface{} {
+	val, err := c.c.Get(c.prefix + key).Result()
+	if err != nil {
+		return nil
+	}
+	return val
+}
+
+// Delete deletes cached value by given key.
+func (c *RedisCacher) Delete(key string) error {
+	key = c.prefix + key
+	if err := c.c.Del(key).Err(); err != nil {
+		return err
+	}
+
+	if c.occupyMode {
+		return nil
+	}
+	return c.c.HDel(c.hsetName, key).Err()
+}
+
+// Incr increases cached int-type value by given key as a counter.
+func (c *RedisCacher) Incr(key string) error {
+	if !c.IsExist(key) {
+		return fmt.Errorf("key '%s' not exist", key)
+	}
+	return c.c.Incr(c.prefix + key).Err()
+}
+
+// Decr decreases cached int-type value by given key as a counter.
+func (c *RedisCacher) Decr(key string) error {
+	if !c.IsExist(key) {
+		return fmt.Errorf("key '%s' not exist", key)
+	}
+	return c.c.Decr(c.prefix + key).Err()
+}
+
+// IsExist returns true if cached value exists.
+func (c *RedisCacher) IsExist(key string) bool {
+	if c.c.Exists(c.prefix + key).Val() {
+		return true
+	}
+
+	if !c.occupyMode {
+		c.c.HDel(c.hsetName, c.prefix+key)
+	}
+	return false
+}
+
+// Flush deletes all cached data.
+func (c *RedisCacher) Flush() error {
+	if c.occupyMode {
+		return c.c.FlushDb().Err()
+	}
+
+	keys, err := c.c.HKeys(c.hsetName).Result()
+	if err != nil {
+		return err
+	}
+	if err = c.c.Del(keys...).Err(); err != nil {
+		return err
+	}
+	return c.c.Del(c.hsetName).Err()
+}
+
+// StartAndGC starts GC routine based on config string settings.
+// AdapterConfig: network=tcp,addr=:6379,password=macaron,db=0,pool_size=100,idle_timeout=180,hset_name=MacaronCache,prefix=cache:
+func (c *RedisCacher) StartAndGC(opts cache.Options) error {
+	c.hsetName = "MacaronCache"
+	c.occupyMode = opts.OccupyMode
+
+	cfg, err := ini.Load([]byte(strings.Replace(opts.AdapterConfig, ",", "\n", -1)))
+	if err != nil {
+		return err
+	}
+
+	opt := &redis.Options{
+		Network: "tcp",
+	}
+	for k, v := range cfg.Section("").KeysHash() {
+		switch k {
+		case "network":
+			opt.Network = v
+		case "addr":
+			opt.Addr = v
+		case "password":
+			opt.Password = v
+		case "db":
+			opt.DB = com.StrTo(v).MustInt64()
+		case "pool_size":
+			opt.PoolSize = com.StrTo(v).MustInt()
+		case "idle_timeout":
+			opt.IdleTimeout, err = time.ParseDuration(v + "s")
+			if err != nil {
+				return fmt.Errorf("error parsing idle timeout: %v", err)
+			}
+		case "hset_name":
+			c.hsetName = v
+		case "prefix":
+			c.prefix = v
+		default:
+			return fmt.Errorf("session/redis: unsupported option '%s'", k)
+		}
+	}
+
+	c.c = redis.NewClient(opt)
+	if err = c.c.Ping().Err(); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func init() {
+	cache.Register("redis", &RedisCacher{})
+}

+ 1 - 0
vendor/github.com/go-macaron/cache/redis/redis.goconvey

@@ -0,0 +1 @@
+ignore

+ 84 - 0
vendor/github.com/go-macaron/cache/utils.go

@@ -0,0 +1,84 @@
+// Copyright 2014 The Macaron Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package cache
+
+import (
+	"bytes"
+	"encoding/gob"
+	"errors"
+)
+
+func EncodeGob(item *Item) ([]byte, error) {
+	buf := bytes.NewBuffer(nil)
+	err := gob.NewEncoder(buf).Encode(item)
+	return buf.Bytes(), err
+}
+
+func DecodeGob(data []byte, out *Item) error {
+	buf := bytes.NewBuffer(data)
+	return gob.NewDecoder(buf).Decode(&out)
+}
+
+func Incr(val interface{}) (interface{}, error) {
+	switch val.(type) {
+	case int:
+		val = val.(int) + 1
+	case int32:
+		val = val.(int32) + 1
+	case int64:
+		val = val.(int64) + 1
+	case uint:
+		val = val.(uint) + 1
+	case uint32:
+		val = val.(uint32) + 1
+	case uint64:
+		val = val.(uint64) + 1
+	default:
+		return val, errors.New("item value is not int-type")
+	}
+	return val, nil
+}
+
+func Decr(val interface{}) (interface{}, error) {
+	switch val.(type) {
+	case int:
+		val = val.(int) - 1
+	case int32:
+		val = val.(int32) - 1
+	case int64:
+		val = val.(int64) - 1
+	case uint:
+		if val.(uint) > 0 {
+			val = val.(uint) - 1
+		} else {
+			return val, errors.New("item value is less than 0")
+		}
+	case uint32:
+		if val.(uint32) > 0 {
+			val = val.(uint32) - 1
+		} else {
+			return val, errors.New("item value is less than 0")
+		}
+	case uint64:
+		if val.(uint64) > 0 {
+			val = val.(uint64) - 1
+		} else {
+			return val, errors.New("item value is less than 0")
+		}
+	default:
+		return val, errors.New("item value is not int-type")
+	}
+	return val, nil
+}

+ 191 - 0
vendor/github.com/go-macaron/captcha/LICENSE

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

+ 16 - 0
vendor/github.com/go-macaron/captcha/README.md

@@ -0,0 +1,16 @@
+# captcha [![Build Status](https://travis-ci.org/go-macaron/captcha.svg?branch=master)](https://travis-ci.org/go-macaron/captcha)
+
+Middleware captcha provides captcha service for [Macaron](https://github.com/go-macaron/macaron).
+
+### Installation
+
+	go get github.com/go-macaron/captcha
+
+## Getting Help
+
+- [API Reference](https://gowalker.org/github.com/go-macaron/captcha)
+- [Documentation](http://go-macaron.com/docs/middlewares/captcha)
+
+## License
+
+This project is under the Apache License, Version 2.0. See the [LICENSE](LICENSE) file for the full license text.

+ 241 - 0
vendor/github.com/go-macaron/captcha/captcha.go

@@ -0,0 +1,241 @@
+// Copyright 2013 Beego Authors
+// Copyright 2014 The Macaron Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+// Package captcha a middleware that provides captcha service for Macaron.
+package captcha
+
+import (
+	"fmt"
+	"html/template"
+	"path"
+	"strings"
+
+	"github.com/Unknwon/com"
+	"github.com/go-macaron/cache"
+	"gopkg.in/macaron.v1"
+)
+
+const _VERSION = "0.1.0"
+
+func Version() string {
+	return _VERSION
+}
+
+var (
+	defaultChars = []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
+)
+
+// Captcha represents a captcha service.
+type Captcha struct {
+	store            cache.Cache
+	SubURL           string
+	URLPrefix        string
+	FieldIdName      string
+	FieldCaptchaName string
+	StdWidth         int
+	StdHeight        int
+	ChallengeNums    int
+	Expiration       int64
+	CachePrefix      string
+}
+
+// generate key string
+func (c *Captcha) key(id string) string {
+	return c.CachePrefix + id
+}
+
+// generate rand chars with default chars
+func (c *Captcha) genRandChars() string {
+	return string(com.RandomCreateBytes(c.ChallengeNums, defaultChars...))
+}
+
+// tempalte func for output html
+func (c *Captcha) CreateHtml() template.HTML {
+	value, err := c.CreateCaptcha()
+	if err != nil {
+		panic(fmt.Errorf("fail to create captcha: %v", err))
+	}
+	return template.HTML(fmt.Sprintf(`<input type="hidden" name="%s" value="%s">
+	<a class="captcha" href="javascript:">
+		<img onclick="this.src=('%s%s%s.png?reload='+(new Date()).getTime())" class="captcha-img" src="%s%s%s.png">
+	</a>`, c.FieldIdName, value, c.SubURL, c.URLPrefix, value, c.SubURL, c.URLPrefix, value))
+}
+
+// create a new captcha id
+func (c *Captcha) CreateCaptcha() (string, error) {
+	id := string(com.RandomCreateBytes(15))
+	if err := c.store.Put(c.key(id), c.genRandChars(), c.Expiration); err != nil {
+		return "", err
+	}
+	return id, nil
+}
+
+// verify from a request
+func (c *Captcha) VerifyReq(req macaron.Request) bool {
+	req.ParseForm()
+	return c.Verify(req.Form.Get(c.FieldIdName), req.Form.Get(c.FieldCaptchaName))
+}
+
+// direct verify id and challenge string
+func (c *Captcha) Verify(id string, challenge string) bool {
+	if len(challenge) == 0 || len(id) == 0 {
+		return false
+	}
+
+	var chars string
+
+	key := c.key(id)
+
+	if v, ok := c.store.Get(key).(string); ok {
+		chars = v
+	} else {
+		return false
+	}
+
+	defer c.store.Delete(key)
+
+	if len(chars) != len(challenge) {
+		return false
+	}
+
+	// verify challenge
+	for i, c := range []byte(chars) {
+		if c != challenge[i]-48 {
+			return false
+		}
+	}
+
+	return true
+}
+
+type Options struct {
+	// Suburl path. Default is empty.
+	SubURL string
+	// URL prefix of getting captcha pictures. Default is "/captcha/".
+	URLPrefix string
+	// Hidden input element ID. Default is "captcha_id".
+	FieldIdName string
+	// User input value element name in request form. Default is "captcha".
+	FieldCaptchaName string
+	// Challenge number. Default is 6.
+	ChallengeNums int
+	// Captcha image width. Default is 240.
+	Width int
+	// Captcha image height. Default is 80.
+	Height int
+	// Captcha expiration time in seconds. Default is 600.
+	Expiration int64
+	// Cache key prefix captcha characters. Default is "captcha_".
+	CachePrefix string
+}
+
+func prepareOptions(options []Options) Options {
+	var opt Options
+	if len(options) > 0 {
+		opt = options[0]
+	}
+
+	opt.SubURL = strings.TrimSuffix(opt.SubURL, "/")
+
+	// Defaults.
+	if len(opt.URLPrefix) == 0 {
+		opt.URLPrefix = "/captcha/"
+	} else if opt.URLPrefix[len(opt.URLPrefix)-1] != '/' {
+		opt.URLPrefix += "/"
+	}
+	if len(opt.FieldIdName) == 0 {
+		opt.FieldIdName = "captcha_id"
+	}
+	if len(opt.FieldCaptchaName) == 0 {
+		opt.FieldCaptchaName = "captcha"
+	}
+	if opt.ChallengeNums == 0 {
+		opt.ChallengeNums = 6
+	}
+	if opt.Width == 0 {
+		opt.Width = stdWidth
+	}
+	if opt.Height == 0 {
+		opt.Height = stdHeight
+	}
+	if opt.Expiration == 0 {
+		opt.Expiration = 600
+	}
+	if len(opt.CachePrefix) == 0 {
+		opt.CachePrefix = "captcha_"
+	}
+
+	return opt
+}
+
+// NewCaptcha initializes and returns a captcha with given options.
+func NewCaptcha(opt Options) *Captcha {
+	return &Captcha{
+		SubURL:           opt.SubURL,
+		URLPrefix:        opt.URLPrefix,
+		FieldIdName:      opt.FieldIdName,
+		FieldCaptchaName: opt.FieldCaptchaName,
+		StdWidth:         opt.Width,
+		StdHeight:        opt.Height,
+		ChallengeNums:    opt.ChallengeNums,
+		Expiration:       opt.Expiration,
+		CachePrefix:      opt.CachePrefix,
+	}
+}
+
+// Captchaer is a middleware that maps a captcha.Captcha service into the Macaron handler chain.
+// An single variadic captcha.Options struct can be optionally provided to configure.
+// This should be register after cache.Cacher.
+func Captchaer(options ...Options) macaron.Handler {
+	return func(ctx *macaron.Context, cache cache.Cache) {
+		cpt := NewCaptcha(prepareOptions(options))
+		cpt.store = cache
+
+		if strings.HasPrefix(ctx.Req.URL.Path, cpt.URLPrefix) {
+			var chars string
+			id := path.Base(ctx.Req.URL.Path)
+			if i := strings.Index(id, "."); i > -1 {
+				id = id[:i]
+			}
+			key := cpt.key(id)
+
+			// Reload captcha.
+			if len(ctx.Query("reload")) > 0 {
+				chars = cpt.genRandChars()
+				if err := cpt.store.Put(key, chars, cpt.Expiration); err != nil {
+					ctx.Status(500)
+					ctx.Write([]byte("captcha reload error"))
+					panic(fmt.Errorf("reload captcha: %v", err))
+				}
+			} else {
+				if v, ok := cpt.store.Get(key).(string); ok {
+					chars = v
+				} else {
+					ctx.Status(404)
+					ctx.Write([]byte("captcha not found"))
+					return
+				}
+			}
+
+			if _, err := NewImage([]byte(chars), cpt.StdWidth, cpt.StdHeight).WriteTo(ctx.Resp); err != nil {
+				panic(fmt.Errorf("write captcha: %v", err))
+			}
+			return
+		}
+
+		ctx.Data["Captcha"] = cpt
+		ctx.Map(cpt)
+	}
+}

+ 498 - 0
vendor/github.com/go-macaron/captcha/image.go

@@ -0,0 +1,498 @@
+// Copyright 2013 Beego Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package captcha
+
+import (
+	"bytes"
+	"image"
+	"image/color"
+	"image/png"
+	"io"
+	"math"
+)
+
+const (
+	fontWidth  = 11
+	fontHeight = 18
+	blackChar  = 1
+
+	// Standard width and height of a captcha image.
+	stdWidth  = 240
+	stdHeight = 80
+
+	// Maximum absolute skew factor of a single digit.
+	maxSkew = 0.7
+	// Number of background circles.
+	circleCount = 20
+)
+
+var font = [][]byte{
+	{ // 0
+		0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0,
+		0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0,
+		0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0,
+		0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0,
+		1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0,
+		1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
+		1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
+		1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
+		1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
+		1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
+		1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
+		1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
+		1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
+		1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1,
+		0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0,
+		0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0,
+		0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0,
+		0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0,
+	},
+	{ // 1
+		0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
+		0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0,
+		0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0,
+		0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0,
+		0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0,
+		0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
+		0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+		0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	},
+	{ // 2
+		0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0,
+		0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,
+		1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0,
+		0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0,
+		0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
+		0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
+		0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
+		0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
+		0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0,
+		0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
+		0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0,
+		0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0,
+		0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0,
+		0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
+		0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	},
+	{ // 3
+		0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0,
+		1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,
+		1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0,
+		0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
+		0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
+		0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
+		0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0,
+		0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0,
+		0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0,
+		0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
+		0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
+		1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0,
+		1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,
+		0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
+	},
+	{ // 4
+		0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
+		0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0,
+		0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0,
+		0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0,
+		0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0,
+		0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0,
+		0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0,
+		0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0,
+		0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0,
+		0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0,
+		1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0,
+		1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
+		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+		0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
+	},
+	{ // 5
+		0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
+		0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
+		0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+		0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+		0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+		0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+		0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
+		0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0,
+		0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
+		0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
+		1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0,
+		1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,
+		0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0,
+	},
+	{ // 6
+		0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0,
+		0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0,
+		0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0,
+		0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+		0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+		0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0,
+		1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0,
+		1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0,
+		1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1,
+		1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
+		1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
+		1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
+		1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
+		0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1,
+		0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0,
+		0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0,
+		0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0,
+	},
+	{ // 7
+		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+		1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1,
+		1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0,
+		0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
+		0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0,
+		0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
+		0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0,
+		0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0,
+		0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
+		0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0,
+		0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0,
+		0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0,
+		0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0,
+		0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0,
+	},
+	{ // 8
+		0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0,
+		0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0,
+		0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1,
+		0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1,
+		0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1,
+		0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1,
+		0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0,
+		0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0,
+		0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0,
+		0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0,
+		0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0,
+		1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1,
+		1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
+		1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
+		1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
+		1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0,
+		0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
+		0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0,
+	},
+	{ // 9
+		0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0,
+		0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,
+		0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0,
+		1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0,
+		1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
+		1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
+		1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,
+		1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1,
+		0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1,
+		0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1,
+		0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1,
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
+		0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
+		0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
+		0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0,
+		0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0,
+		0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
+		0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
+	},
+}
+
+type Image struct {
+	*image.Paletted
+	numWidth  int
+	numHeight int
+	dotSize   int
+}
+
+var prng = &siprng{}
+
+// randIntn returns a pseudorandom non-negative int in range [0, n).
+func randIntn(n int) int {
+	return prng.Intn(n)
+}
+
+// randInt returns a pseudorandom int in range [from, to].
+func randInt(from, to int) int {
+	return prng.Intn(to+1-from) + from
+}
+
+// randFloat returns a pseudorandom float64 in range [from, to].
+func randFloat(from, to float64) float64 {
+	return (to-from)*prng.Float64() + from
+}
+
+func randomPalette() color.Palette {
+	p := make([]color.Color, circleCount+1)
+	// Transparent color.
+	p[0] = color.RGBA{0xFF, 0xFF, 0xFF, 0x00}
+	// Primary color.
+	prim := color.RGBA{
+		uint8(randIntn(129)),
+		uint8(randIntn(129)),
+		uint8(randIntn(129)),
+		0xFF,
+	}
+	p[1] = prim
+	// Circle colors.
+	for i := 2; i <= circleCount; i++ {
+		p[i] = randomBrightness(prim, 255)
+	}
+	return p
+}
+
+// NewImage returns a new captcha image of the given width and height with the
+// given digits, where each digit must be in range 0-9.
+func NewImage(digits []byte, width, height int) *Image {
+	m := new(Image)
+	m.Paletted = image.NewPaletted(image.Rect(0, 0, width, height), randomPalette())
+	m.calculateSizes(width, height, len(digits))
+	// Randomly position captcha inside the image.
+	maxx := width - (m.numWidth+m.dotSize)*len(digits) - m.dotSize
+	maxy := height - m.numHeight - m.dotSize*2
+	var border int
+	if width > height {
+		border = height / 5
+	} else {
+		border = width / 5
+	}
+	x := randInt(border, maxx-border)
+	y := randInt(border, maxy-border)
+	// Draw digits.
+	for _, n := range digits {
+		m.drawDigit(font[n], x, y)
+		x += m.numWidth + m.dotSize
+	}
+	// Draw strike-through line.
+	m.strikeThrough()
+	// Apply wave distortion.
+	m.distort(randFloat(5, 10), randFloat(100, 200))
+	// Fill image with random circles.
+	m.fillWithCircles(circleCount, m.dotSize)
+	return m
+}
+
+// encodedPNG encodes an image to PNG and returns
+// the result as a byte slice.
+func (m *Image) encodedPNG() []byte {
+	var buf bytes.Buffer
+	if err := png.Encode(&buf, m.Paletted); err != nil {
+		panic(err.Error())
+	}
+	return buf.Bytes()
+}
+
+// WriteTo writes captcha image in PNG format into the given writer.
+func (m *Image) WriteTo(w io.Writer) (int64, error) {
+	n, err := w.Write(m.encodedPNG())
+	return int64(n), err
+}
+
+func (m *Image) calculateSizes(width, height, ncount int) {
+	// Goal: fit all digits inside the image.
+	var border int
+	if width > height {
+		border = height / 4
+	} else {
+		border = width / 4
+	}
+	// Convert everything to floats for calculations.
+	w := float64(width - border*2)
+	h := float64(height - border*2)
+	// fw takes into account 1-dot spacing between digits.
+	fw := float64(fontWidth + 1)
+	fh := float64(fontHeight)
+	nc := float64(ncount)
+	// Calculate the width of a single digit taking into account only the
+	// width of the image.
+	nw := w / nc
+	// Calculate the height of a digit from this width.
+	nh := nw * fh / fw
+	// Digit too high?
+	if nh > h {
+		// Fit digits based on height.
+		nh = h
+		nw = fw / fh * nh
+	}
+	// Calculate dot size.
+	m.dotSize = int(nh / fh)
+	// Save everything, making the actual width smaller by 1 dot to account
+	// for spacing between digits.
+	m.numWidth = int(nw) - m.dotSize
+	m.numHeight = int(nh)
+}
+
+func (m *Image) drawHorizLine(fromX, toX, y int, colorIdx uint8) {
+	for x := fromX; x <= toX; x++ {
+		m.SetColorIndex(x, y, colorIdx)
+	}
+}
+
+func (m *Image) drawCircle(x, y, radius int, colorIdx uint8) {
+	f := 1 - radius
+	dfx := 1
+	dfy := -2 * radius
+	xo := 0
+	yo := radius
+
+	m.SetColorIndex(x, y+radius, colorIdx)
+	m.SetColorIndex(x, y-radius, colorIdx)
+	m.drawHorizLine(x-radius, x+radius, y, colorIdx)
+
+	for xo < yo {
+		if f >= 0 {
+			yo--
+			dfy += 2
+			f += dfy
+		}
+		xo++
+		dfx += 2
+		f += dfx
+		m.drawHorizLine(x-xo, x+xo, y+yo, colorIdx)
+		m.drawHorizLine(x-xo, x+xo, y-yo, colorIdx)
+		m.drawHorizLine(x-yo, x+yo, y+xo, colorIdx)
+		m.drawHorizLine(x-yo, x+yo, y-xo, colorIdx)
+	}
+}
+
+func (m *Image) fillWithCircles(n, maxradius int) {
+	maxx := m.Bounds().Max.X
+	maxy := m.Bounds().Max.Y
+	for i := 0; i < n; i++ {
+		colorIdx := uint8(randInt(1, circleCount-1))
+		r := randInt(1, maxradius)
+		m.drawCircle(randInt(r, maxx-r), randInt(r, maxy-r), r, colorIdx)
+	}
+}
+
+func (m *Image) strikeThrough() {
+	maxx := m.Bounds().Max.X
+	maxy := m.Bounds().Max.Y
+	y := randInt(maxy/3, maxy-maxy/3)
+	amplitude := randFloat(5, 20)
+	period := randFloat(80, 180)
+	dx := 2.0 * math.Pi / period
+	for x := 0; x < maxx; x++ {
+		xo := amplitude * math.Cos(float64(y)*dx)
+		yo := amplitude * math.Sin(float64(x)*dx)
+		for yn := 0; yn < m.dotSize; yn++ {
+			r := randInt(0, m.dotSize)
+			m.drawCircle(x+int(xo), y+int(yo)+(yn*m.dotSize), r/2, 1)
+		}
+	}
+}
+
+func (m *Image) drawDigit(digit []byte, x, y int) {
+	skf := randFloat(-maxSkew, maxSkew)
+	xs := float64(x)
+	r := m.dotSize / 2
+	y += randInt(-r, r)
+	for yo := 0; yo < fontHeight; yo++ {
+		for xo := 0; xo < fontWidth; xo++ {
+			if digit[yo*fontWidth+xo] != blackChar {
+				continue
+			}
+			m.drawCircle(x+xo*m.dotSize, y+yo*m.dotSize, r, 1)
+		}
+		xs += skf
+		x = int(xs)
+	}
+}
+
+func (m *Image) distort(amplude float64, period float64) {
+	w := m.Bounds().Max.X
+	h := m.Bounds().Max.Y
+
+	oldm := m.Paletted
+	newm := image.NewPaletted(image.Rect(0, 0, w, h), oldm.Palette)
+
+	dx := 2.0 * math.Pi / period
+	for x := 0; x < w; x++ {
+		for y := 0; y < h; y++ {
+			xo := amplude * math.Sin(float64(y)*dx)
+			yo := amplude * math.Cos(float64(x)*dx)
+			newm.SetColorIndex(x, y, oldm.ColorIndexAt(x+int(xo), y+int(yo)))
+		}
+	}
+	m.Paletted = newm
+}
+
+func randomBrightness(c color.RGBA, max uint8) color.RGBA {
+	minc := min3(c.R, c.G, c.B)
+	maxc := max3(c.R, c.G, c.B)
+	if maxc > max {
+		return c
+	}
+	n := randIntn(int(max-maxc)) - int(minc)
+	return color.RGBA{
+		uint8(int(c.R) + n),
+		uint8(int(c.G) + n),
+		uint8(int(c.B) + n),
+		uint8(c.A),
+	}
+}
+
+func min3(x, y, z uint8) (m uint8) {
+	m = x
+	if y < m {
+		m = y
+	}
+	if z < m {
+		m = z
+	}
+	return
+}
+
+func max3(x, y, z uint8) (m uint8) {
+	m = x
+	if y > m {
+		m = y
+	}
+	if z > m {
+		m = z
+	}
+	return
+}

+ 277 - 0
vendor/github.com/go-macaron/captcha/siprng.go

@@ -0,0 +1,277 @@
+// Copyright 2013 Beego Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package captcha
+
+import (
+	"crypto/rand"
+	"encoding/binary"
+	"io"
+	"sync"
+)
+
+// siprng is PRNG based on SipHash-2-4.
+type siprng struct {
+	mu          sync.Mutex
+	k0, k1, ctr uint64
+}
+
+// siphash implements SipHash-2-4, accepting a uint64 as a message.
+func siphash(k0, k1, m uint64) uint64 {
+	// Initialization.
+	v0 := k0 ^ 0x736f6d6570736575
+	v1 := k1 ^ 0x646f72616e646f6d
+	v2 := k0 ^ 0x6c7967656e657261
+	v3 := k1 ^ 0x7465646279746573
+	t := uint64(8) << 56
+
+	// Compression.
+	v3 ^= m
+
+	// Round 1.
+	v0 += v1
+	v1 = v1<<13 | v1>>(64-13)
+	v1 ^= v0
+	v0 = v0<<32 | v0>>(64-32)
+
+	v2 += v3
+	v3 = v3<<16 | v3>>(64-16)
+	v3 ^= v2
+
+	v0 += v3
+	v3 = v3<<21 | v3>>(64-21)
+	v3 ^= v0
+
+	v2 += v1
+	v1 = v1<<17 | v1>>(64-17)
+	v1 ^= v2
+	v2 = v2<<32 | v2>>(64-32)
+
+	// Round 2.
+	v0 += v1
+	v1 = v1<<13 | v1>>(64-13)
+	v1 ^= v0
+	v0 = v0<<32 | v0>>(64-32)
+
+	v2 += v3
+	v3 = v3<<16 | v3>>(64-16)
+	v3 ^= v2
+
+	v0 += v3
+	v3 = v3<<21 | v3>>(64-21)
+	v3 ^= v0
+
+	v2 += v1
+	v1 = v1<<17 | v1>>(64-17)
+	v1 ^= v2
+	v2 = v2<<32 | v2>>(64-32)
+
+	v0 ^= m
+
+	// Compress last block.
+	v3 ^= t
+
+	// Round 1.
+	v0 += v1
+	v1 = v1<<13 | v1>>(64-13)
+	v1 ^= v0
+	v0 = v0<<32 | v0>>(64-32)
+
+	v2 += v3
+	v3 = v3<<16 | v3>>(64-16)
+	v3 ^= v2
+
+	v0 += v3
+	v3 = v3<<21 | v3>>(64-21)
+	v3 ^= v0
+
+	v2 += v1
+	v1 = v1<<17 | v1>>(64-17)
+	v1 ^= v2
+	v2 = v2<<32 | v2>>(64-32)
+
+	// Round 2.
+	v0 += v1
+	v1 = v1<<13 | v1>>(64-13)
+	v1 ^= v0
+	v0 = v0<<32 | v0>>(64-32)
+
+	v2 += v3
+	v3 = v3<<16 | v3>>(64-16)
+	v3 ^= v2
+
+	v0 += v3
+	v3 = v3<<21 | v3>>(64-21)
+	v3 ^= v0
+
+	v2 += v1
+	v1 = v1<<17 | v1>>(64-17)
+	v1 ^= v2
+	v2 = v2<<32 | v2>>(64-32)
+
+	v0 ^= t
+
+	// Finalization.
+	v2 ^= 0xff
+
+	// Round 1.
+	v0 += v1
+	v1 = v1<<13 | v1>>(64-13)
+	v1 ^= v0
+	v0 = v0<<32 | v0>>(64-32)
+
+	v2 += v3
+	v3 = v3<<16 | v3>>(64-16)
+	v3 ^= v2
+
+	v0 += v3
+	v3 = v3<<21 | v3>>(64-21)
+	v3 ^= v0
+
+	v2 += v1
+	v1 = v1<<17 | v1>>(64-17)
+	v1 ^= v2
+	v2 = v2<<32 | v2>>(64-32)
+
+	// Round 2.
+	v0 += v1
+	v1 = v1<<13 | v1>>(64-13)
+	v1 ^= v0
+	v0 = v0<<32 | v0>>(64-32)
+
+	v2 += v3
+	v3 = v3<<16 | v3>>(64-16)
+	v3 ^= v2
+
+	v0 += v3
+	v3 = v3<<21 | v3>>(64-21)
+	v3 ^= v0
+
+	v2 += v1
+	v1 = v1<<17 | v1>>(64-17)
+	v1 ^= v2
+	v2 = v2<<32 | v2>>(64-32)
+
+	// Round 3.
+	v0 += v1
+	v1 = v1<<13 | v1>>(64-13)
+	v1 ^= v0
+	v0 = v0<<32 | v0>>(64-32)
+
+	v2 += v3
+	v3 = v3<<16 | v3>>(64-16)
+	v3 ^= v2
+
+	v0 += v3
+	v3 = v3<<21 | v3>>(64-21)
+	v3 ^= v0
+
+	v2 += v1
+	v1 = v1<<17 | v1>>(64-17)
+	v1 ^= v2
+	v2 = v2<<32 | v2>>(64-32)
+
+	// Round 4.
+	v0 += v1
+	v1 = v1<<13 | v1>>(64-13)
+	v1 ^= v0
+	v0 = v0<<32 | v0>>(64-32)
+
+	v2 += v3
+	v3 = v3<<16 | v3>>(64-16)
+	v3 ^= v2
+
+	v0 += v3
+	v3 = v3<<21 | v3>>(64-21)
+	v3 ^= v0
+
+	v2 += v1
+	v1 = v1<<17 | v1>>(64-17)
+	v1 ^= v2
+	v2 = v2<<32 | v2>>(64-32)
+
+	return v0 ^ v1 ^ v2 ^ v3
+}
+
+// rekey sets a new PRNG key, which is read from crypto/rand.
+func (p *siprng) rekey() {
+	var k [16]byte
+	if _, err := io.ReadFull(rand.Reader, k[:]); err != nil {
+		panic(err.Error())
+	}
+	p.k0 = binary.LittleEndian.Uint64(k[0:8])
+	p.k1 = binary.LittleEndian.Uint64(k[8:16])
+	p.ctr = 1
+}
+
+// Uint64 returns a new pseudorandom uint64.
+// It rekeys PRNG on the first call and every 64 MB of generated data.
+func (p *siprng) Uint64() uint64 {
+	p.mu.Lock()
+	if p.ctr == 0 || p.ctr > 8*1024*1024 {
+		p.rekey()
+	}
+	v := siphash(p.k0, p.k1, p.ctr)
+	p.ctr++
+	p.mu.Unlock()
+	return v
+}
+
+func (p *siprng) Int63() int64 {
+	return int64(p.Uint64() & 0x7fffffffffffffff)
+}
+
+func (p *siprng) Uint32() uint32 {
+	return uint32(p.Uint64())
+}
+
+func (p *siprng) Int31() int32 {
+	return int32(p.Uint32() & 0x7fffffff)
+}
+
+func (p *siprng) Intn(n int) int {
+	if n <= 0 {
+		panic("invalid argument to Intn")
+	}
+	if n <= 1<<31-1 {
+		return int(p.Int31n(int32(n)))
+	}
+	return int(p.Int63n(int64(n)))
+}
+
+func (p *siprng) Int63n(n int64) int64 {
+	if n <= 0 {
+		panic("invalid argument to Int63n")
+	}
+	max := int64((1 << 63) - 1 - (1<<63)%uint64(n))
+	v := p.Int63()
+	for v > max {
+		v = p.Int63()
+	}
+	return v % n
+}
+
+func (p *siprng) Int31n(n int32) int32 {
+	if n <= 0 {
+		panic("invalid argument to Int31n")
+	}
+	max := int32((1 << 31) - 1 - (1<<31)%uint32(n))
+	v := p.Int31()
+	for v > max {
+		v = p.Int31()
+	}
+	return v % n
+}
+
+func (p *siprng) Float64() float64 { return float64(p.Int63()) / (1 << 63) }

+ 191 - 0
vendor/github.com/go-macaron/csrf/LICENSE

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

+ 18 - 0
vendor/github.com/go-macaron/csrf/README.md

@@ -0,0 +1,18 @@
+# csrf [![Build Status](https://travis-ci.org/go-macaron/csrf.svg?branch=master)](https://travis-ci.org/go-macaron/csrf) [![](http://gocover.io/_badge/github.com/go-macaron/csrf)](http://gocover.io/github.com/go-macaron/csrf)
+
+Middleware csrf generates and validates CSRF tokens for [Macaron](https://github.com/go-macaron/macaron).
+
+[API Reference](https://gowalker.org/github.com/go-macaron/csrf)
+
+### Installation
+
+	go get github.com/go-macaron/csrf
+	
+## Getting Help
+
+- [API Reference](https://gowalker.org/github.com/go-macaron/csrf)
+- [Documentation](http://go-macaron.com/docs/middlewares/csrf)
+
+## License
+
+This project is under the Apache License, Version 2.0. See the [LICENSE](LICENSE) file for the full license text.

+ 251 - 0
vendor/github.com/go-macaron/csrf/csrf.go

@@ -0,0 +1,251 @@
+// Copyright 2013 Martini Authors
+// Copyright 2014 The Macaron Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+// Package csrf is a middleware that generates and validates CSRF tokens for Macaron.
+package csrf
+
+import (
+	"net/http"
+	"time"
+
+	"github.com/Unknwon/com"
+	"github.com/go-macaron/session"
+	"gopkg.in/macaron.v1"
+)
+
+const _VERSION = "0.1.0"
+
+func Version() string {
+	return _VERSION
+}
+
+// CSRF represents a CSRF service and is used to get the current token and validate a suspect token.
+type CSRF interface {
+	// Return HTTP header to search for token.
+	GetHeaderName() string
+	// Return form value to search for token.
+	GetFormName() string
+	// Return cookie name to search for token.
+	GetCookieName() string
+	// Return cookie path
+	GetCookiePath() string
+	// Return the token.
+	GetToken() string
+	// Validate by token.
+	ValidToken(t string) bool
+	// Error replies to the request with a custom function when ValidToken fails.
+	Error(w http.ResponseWriter)
+}
+
+type csrf struct {
+	// Header name value for setting and getting csrf token.
+	Header string
+	// Form name value for setting and getting csrf token.
+	Form string
+	// Cookie name value for setting and getting csrf token.
+	Cookie string
+	//Cookie path
+	CookiePath string
+	// Token generated to pass via header, cookie, or hidden form value.
+	Token string
+	// This value must be unique per user.
+	ID string
+	// Secret used along with the unique id above to generate the Token.
+	Secret string
+	// ErrorFunc is the custom function that replies to the request when ValidToken fails.
+	ErrorFunc func(w http.ResponseWriter)
+}
+
+// GetHeaderName returns the name of the HTTP header for csrf token.
+func (c *csrf) GetHeaderName() string {
+	return c.Header
+}
+
+// GetFormName returns the name of the form value for csrf token.
+func (c *csrf) GetFormName() string {
+	return c.Form
+}
+
+// GetCookieName returns the name of the cookie for csrf token.
+func (c *csrf) GetCookieName() string {
+	return c.Cookie
+}
+
+// GetCookiePath returns the path of the cookie for csrf token.
+func (c *csrf) GetCookiePath() string {
+	return c.CookiePath
+}
+
+// GetToken returns the current token. This is typically used
+// to populate a hidden form in an HTML template.
+func (c *csrf) GetToken() string {
+	return c.Token
+}
+
+// ValidToken validates the passed token against the existing Secret and ID.
+func (c *csrf) ValidToken(t string) bool {
+	return ValidToken(t, c.Secret, c.ID, "POST")
+}
+
+// Error replies to the request when ValidToken fails.
+func (c *csrf) Error(w http.ResponseWriter) {
+	c.ErrorFunc(w)
+}
+
+// Options maintains options to manage behavior of Generate.
+type Options struct {
+	// The global secret value used to generate Tokens.
+	Secret string
+	// HTTP header used to set and get token.
+	Header string
+	// Form value used to set and get token.
+	Form string
+	// Cookie value used to set and get token.
+	Cookie string
+	// Cookie path.
+	CookiePath string
+	// Key used for getting the unique ID per user.
+	SessionKey string
+	// oldSeesionKey saves old value corresponding to SessionKey.
+	oldSeesionKey string
+	// If true, send token via X-CSRFToken header.
+	SetHeader bool
+	// If true, send token via _csrf cookie.
+	SetCookie bool
+	// Set the Secure flag to true on the cookie.
+	Secure bool
+	// Disallow Origin appear in request header.
+	Origin bool
+	// The function called when Validate fails.
+	ErrorFunc func(w http.ResponseWriter)
+}
+
+func prepareOptions(options []Options) Options {
+	var opt Options
+	if len(options) > 0 {
+		opt = options[0]
+	}
+
+	// Defaults.
+	if len(opt.Secret) == 0 {
+		opt.Secret = string(com.RandomCreateBytes(10))
+	}
+	if len(opt.Header) == 0 {
+		opt.Header = "X-CSRFToken"
+	}
+	if len(opt.Form) == 0 {
+		opt.Form = "_csrf"
+	}
+	if len(opt.Cookie) == 0 {
+		opt.Cookie = "_csrf"
+	}
+	if len(opt.CookiePath) == 0 {
+		opt.CookiePath = "/"
+	}
+	if len(opt.SessionKey) == 0 {
+		opt.SessionKey = "uid"
+	}
+	opt.oldSeesionKey = "_old_" + opt.SessionKey
+	if opt.ErrorFunc == nil {
+		opt.ErrorFunc = func(w http.ResponseWriter) {
+			http.Error(w, "Invalid csrf token.", http.StatusBadRequest)
+		}
+	}
+
+	return opt
+}
+
+// Generate maps CSRF to each request. If this request is a Get request, it will generate a new token.
+// Additionally, depending on options set, generated tokens will be sent via Header and/or Cookie.
+func Generate(options ...Options) macaron.Handler {
+	opt := prepareOptions(options)
+	return func(ctx *macaron.Context, sess session.Store) {
+		x := &csrf{
+			Secret:     opt.Secret,
+			Header:     opt.Header,
+			Form:       opt.Form,
+			Cookie:     opt.Cookie,
+			CookiePath: opt.CookiePath,
+			ErrorFunc:  opt.ErrorFunc,
+		}
+		ctx.MapTo(x, (*CSRF)(nil))
+
+		if opt.Origin && len(ctx.Req.Header.Get("Origin")) > 0 {
+			return
+		}
+
+		x.ID = "0"
+		uid := sess.Get(opt.SessionKey)
+		if uid != nil {
+			x.ID = com.ToStr(uid)
+		}
+
+		needsNew := false
+		oldUid := sess.Get(opt.oldSeesionKey)
+		if oldUid == nil || oldUid.(string) != x.ID {
+			needsNew = true
+			sess.Set(opt.oldSeesionKey, x.ID)
+		} else {
+			// If cookie present, map existing token, else generate a new one.
+			if val := ctx.GetCookie(opt.Cookie); len(val) > 0 {
+				// FIXME: test coverage.
+				x.Token = val
+			} else {
+				needsNew = true
+			}
+		}
+
+		if needsNew {
+			// FIXME: actionId.
+			x.Token = GenerateToken(x.Secret, x.ID, "POST")
+			if opt.SetCookie {
+				ctx.SetCookie(opt.Cookie, x.Token, 0, opt.CookiePath, "", false, true, time.Now().AddDate(0, 0, 1))
+			}
+		}
+
+		if opt.SetHeader {
+			ctx.Resp.Header().Add(opt.Header, x.Token)
+		}
+	}
+}
+
+// Csrfer maps CSRF to each request. If this request is a Get request, it will generate a new token.
+// Additionally, depending on options set, generated tokens will be sent via Header and/or Cookie.
+func Csrfer(options ...Options) macaron.Handler {
+	return Generate(options...)
+}
+
+// Validate should be used as a per route middleware. It attempts to get a token from a "X-CSRFToken"
+// HTTP header and then a "_csrf" form value. If one of these is found, the token will be validated
+// using ValidToken. If this validation fails, custom Error is sent in the reply.
+// If neither a header or form value is found, http.StatusBadRequest is sent.
+func Validate(ctx *macaron.Context, x CSRF) {
+	if token := ctx.Req.Header.Get(x.GetHeaderName()); len(token) > 0 {
+		if !x.ValidToken(token) {
+			ctx.SetCookie(x.GetCookieName(), "", -1, x.GetCookiePath())
+			x.Error(ctx.Resp)
+		}
+		return
+	}
+	if token := ctx.Req.FormValue(x.GetFormName()); len(token) > 0 {
+		if !x.ValidToken(token) {
+			ctx.SetCookie(x.GetCookieName(), "", -1, x.GetCookiePath())
+			x.Error(ctx.Resp)
+		}
+		return
+	}
+
+	http.Error(ctx.Resp, "Bad Request: no CSRF token present", http.StatusBadRequest)
+}

+ 97 - 0
vendor/github.com/go-macaron/csrf/xsrf.go

@@ -0,0 +1,97 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+// Copyright 2014 The Macaron Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package csrf
+
+import (
+	"bytes"
+	"crypto/hmac"
+	"crypto/sha1"
+	"crypto/subtle"
+	"encoding/base64"
+	"fmt"
+	"strconv"
+	"strings"
+	"time"
+)
+
+// The duration that XSRF tokens are valid.
+// It is exported so clients may set cookie timeouts that match generated tokens.
+const TIMEOUT = 24 * time.Hour
+
+// clean sanitizes a string for inclusion in a token by replacing all ":"s.
+func clean(s string) string {
+	return strings.Replace(s, ":", "_", -1)
+}
+
+// GenerateToken returns a URL-safe secure XSRF token that expires in 24 hours.
+//
+// key is a secret key for your application.
+// userID is a unique identifier for the user.
+// actionID is the action the user is taking (e.g. POSTing to a particular path).
+func GenerateToken(key, userID, actionID string) string {
+	return generateTokenAtTime(key, userID, actionID, time.Now())
+}
+
+// generateTokenAtTime is like Generate, but returns a token that expires 24 hours from now.
+func generateTokenAtTime(key, userID, actionID string, now time.Time) string {
+	h := hmac.New(sha1.New, []byte(key))
+	fmt.Fprintf(h, "%s:%s:%d", clean(userID), clean(actionID), now.UnixNano())
+	tok := fmt.Sprintf("%s:%d", h.Sum(nil), now.UnixNano())
+	return base64.URLEncoding.EncodeToString([]byte(tok))
+}
+
+// Valid returns true if token is a valid, unexpired token returned by Generate.
+func ValidToken(token, key, userID, actionID string) bool {
+	return validTokenAtTime(token, key, userID, actionID, time.Now())
+}
+
+// validTokenAtTime is like Valid, but it uses now to check if the token is expired.
+func validTokenAtTime(token, key, userID, actionID string, now time.Time) bool {
+	// Decode the token.
+	data, err := base64.URLEncoding.DecodeString(token)
+	if err != nil {
+		return false
+	}
+
+	// Extract the issue time of the token.
+	sep := bytes.LastIndex(data, []byte{':'})
+	if sep < 0 {
+		return false
+	}
+	nanos, err := strconv.ParseInt(string(data[sep+1:]), 10, 64)
+	if err != nil {
+		return false
+	}
+	issueTime := time.Unix(0, nanos)
+
+	// Check that the token is not expired.
+	if now.Sub(issueTime) >= TIMEOUT {
+		return false
+	}
+
+	// Check that the token is not from the future.
+	// Allow 1 minute grace period in case the token is being verified on a
+	// machine whose clock is behind the machine that issued the token.
+	if issueTime.After(now.Add(1 * time.Minute)) {
+		return false
+	}
+
+	expected := generateTokenAtTime(key, userID, actionID, issueTime)
+
+	// Check that the token matches the expected value.
+	// Use constant time comparison to avoid timing attacks.
+	return subtle.ConstantTimeCompare([]byte(token), []byte(expected)) == 1
+}

+ 191 - 0
vendor/github.com/go-macaron/gzip/LICENSE

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

+ 20 - 0
vendor/github.com/go-macaron/gzip/README.md

@@ -0,0 +1,20 @@
+# gzip [![Build Status](https://travis-ci.org/go-macaron/gzip.svg?branch=master)](https://travis-ci.org/go-macaron/gzip) [![](http://gocover.io/_badge/github.com/go-macaron/gzip)](http://gocover.io/github.com/go-macaron/gzip)
+
+Middleware gzip provides compress to responses for [Macaron](https://github.com/go-macaron/macaron).
+
+### Installation
+
+	go get github.com/go-macaron/gzip
+
+## Getting Help
+
+- [API Reference](https://gowalker.org/github.com/go-macaron/gzip)
+- [Documentation](http://go-macaron.com/docs/middlewares/gzip)
+
+## Credits
+
+This package is a modified version of [martini-contrib/gzip](https://github.com/martini-contrib/gzip).
+
+## License
+
+This project is under the Apache License, Version 2.0. See the [LICENSE](LICENSE) file for the full license text.

+ 121 - 0
vendor/github.com/go-macaron/gzip/gzip.go

@@ -0,0 +1,121 @@
+// Copyright 2013 Martini Authors
+// Copyright 2015 The Macaron Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package gzip
+
+import (
+	"bufio"
+	"fmt"
+	"net"
+	"net/http"
+	"strings"
+
+	"github.com/klauspost/compress/gzip"
+	"gopkg.in/macaron.v1"
+)
+
+const (
+	_HEADER_ACCEPT_ENCODING  = "Accept-Encoding"
+	_HEADER_CONTENT_ENCODING = "Content-Encoding"
+	_HEADER_CONTENT_LENGTH   = "Content-Length"
+	_HEADER_CONTENT_TYPE     = "Content-Type"
+	_HEADER_VARY             = "Vary"
+)
+
+// Options represents a struct for specifying configuration options for the GZip middleware.
+type Options struct {
+	// Compression level. Can be DefaultCompression(-1), ConstantCompression(-2)
+	// or any integer value between BestSpeed(1) and BestCompression(9) inclusive.
+	CompressionLevel int
+}
+
+func isCompressionLevelValid(level int) bool {
+	return level == gzip.DefaultCompression ||
+		level == gzip.ConstantCompression ||
+		(level >= gzip.BestSpeed && level <= gzip.BestCompression)
+}
+
+func prepareOptions(options []Options) Options {
+	var opt Options
+	if len(options) > 0 {
+		opt = options[0]
+	}
+
+	if !isCompressionLevelValid(opt.CompressionLevel) {
+		// For web content, level 4 seems to be a sweet spot.
+		opt.CompressionLevel = 4
+	}
+	return opt
+}
+
+// Gziper returns a Handler that adds gzip compression to all requests.
+// Make sure to include the Gzip middleware above other middleware
+// that alter the response body (like the render middleware).
+func Gziper(options ...Options) macaron.Handler {
+	opt := prepareOptions(options)
+
+	return func(ctx *macaron.Context) {
+		if !strings.Contains(ctx.Req.Header.Get(_HEADER_ACCEPT_ENCODING), "gzip") {
+			return
+		}
+
+		headers := ctx.Resp.Header()
+		headers.Set(_HEADER_CONTENT_ENCODING, "gzip")
+		headers.Set(_HEADER_VARY, _HEADER_ACCEPT_ENCODING)
+
+		// We've made sure compression level is valid in prepareGzipOptions,
+		// no need to check same error again.
+		gz, err := gzip.NewWriterLevel(ctx.Resp, opt.CompressionLevel)
+		if err != nil {
+			panic(err.Error())
+		}
+		defer gz.Close()
+
+		gzw := gzipResponseWriter{gz, ctx.Resp}
+		ctx.Resp = gzw
+		ctx.MapTo(gzw, (*http.ResponseWriter)(nil))
+
+		// Check if render middleware has been registered,
+		// if yes, we need to modify ResponseWriter for it as well.
+		if _, ok := ctx.Render.(*macaron.DummyRender); !ok {
+			ctx.Render.SetResponseWriter(gzw)
+		}
+
+		ctx.Next()
+
+		// delete content length after we know we have been written to
+		gzw.Header().Del("Content-Length")
+	}
+}
+
+type gzipResponseWriter struct {
+	w *gzip.Writer
+	macaron.ResponseWriter
+}
+
+func (grw gzipResponseWriter) Write(p []byte) (int, error) {
+	if len(grw.Header().Get(_HEADER_CONTENT_TYPE)) == 0 {
+		grw.Header().Set(_HEADER_CONTENT_TYPE, http.DetectContentType(p))
+	}
+	return grw.w.Write(p)
+}
+
+func (grw gzipResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+	hijacker, ok := grw.ResponseWriter.(http.Hijacker)
+	if !ok {
+		return nil, nil, fmt.Errorf("the ResponseWriter doesn't support the Hijacker interface")
+	}
+	return hijacker.Hijack()
+}

+ 191 - 0
vendor/github.com/go-macaron/i18n/LICENSE

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

+ 16 - 0
vendor/github.com/go-macaron/i18n/README.md

@@ -0,0 +1,16 @@
+# i18n [![Build Status](https://travis-ci.org/go-macaron/i18n.svg?branch=master)](https://travis-ci.org/go-macaron/i18n) [![](http://gocover.io/_badge/github.com/go-macaron/i18n)](http://gocover.io/github.com/go-macaron/i18n)
+
+Middleware i18n provides app Internationalization and Localization for [Macaron](https://github.com/go-macaron/macaron).
+
+### Installation
+
+	go get github.com/go-macaron/i18n
+	
+## Getting Help
+
+- [API Reference](https://gowalker.org/github.com/go-macaron/i18n)
+- [Documentation](http://go-macaron.com/docs/middlewares/i18n)
+
+## License
+
+This project is under the Apache License, Version 2.0. See the [LICENSE](LICENSE) file for the full license text.

+ 225 - 0
vendor/github.com/go-macaron/i18n/i18n.go

@@ -0,0 +1,225 @@
+// Copyright 2014 The Macaron Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+// Package i18n is a middleware that provides app Internationalization and Localization of Macaron.
+package i18n
+
+import (
+	"fmt"
+	"path"
+	"strings"
+
+	"github.com/Unknwon/com"
+	"github.com/Unknwon/i18n"
+	"golang.org/x/text/language"
+	"gopkg.in/macaron.v1"
+)
+
+const _VERSION = "0.3.0"
+
+func Version() string {
+	return _VERSION
+}
+
+// initLocales initializes language type list and Accept-Language header matcher.
+func initLocales(opt Options) language.Matcher {
+	tags := make([]language.Tag, len(opt.Langs))
+	for i, lang := range opt.Langs {
+		tags[i] = language.Raw.Make(lang)
+		fname := fmt.Sprintf(opt.Format, lang)
+		// Append custom locale file.
+		custom := []interface{}{}
+		customPath := path.Join(opt.CustomDirectory, fname)
+		if com.IsFile(customPath) {
+			custom = append(custom, customPath)
+		}
+
+		var locale interface{}
+		if data, ok := opt.Files[fname]; ok {
+			locale = data
+		} else {
+			locale = path.Join(opt.Directory, fname)
+		}
+
+		err := i18n.SetMessageWithDesc(lang, opt.Names[i], locale, custom...)
+		if err != nil && err != i18n.ErrLangAlreadyExist {
+			panic(fmt.Errorf("fail to set message file(%s): %v", lang, err))
+		}
+	}
+	return language.NewMatcher(tags)
+}
+
+// A Locale describles the information of localization.
+type Locale struct {
+	i18n.Locale
+}
+
+// Language returns language current locale represents.
+func (l Locale) Language() string {
+	return l.Lang
+}
+
+// Options represents a struct for specifying configuration options for the i18n middleware.
+type Options struct {
+	// Suburl of path. Default is empty.
+	SubURL string
+	// Directory to load locale files. Default is "conf/locale"
+	Directory string
+	// File stores actual data of locale files. Used for in-memory purpose.
+	Files map[string][]byte
+	// Custom directory to overload locale files. Default is "custom/conf/locale"
+	CustomDirectory string
+	// Langauges that will be supported, order is meaningful.
+	Langs []string
+	// Human friendly names corresponding to Langs list.
+	Names []string
+	// Default language locale, leave empty to remain unset.
+	DefaultLang string
+	// Locale file naming style. Default is "locale_%s.ini".
+	Format string
+	// Name of language parameter name in URL. Default is "lang".
+	Parameter string
+	// Redirect when user uses get parameter to specify language.
+	Redirect bool
+	// Name that maps into template variable. Default is "i18n".
+	TmplName string
+	// Configuration section name. Default is "i18n".
+	Section string
+}
+
+func prepareOptions(options []Options) Options {
+	var opt Options
+	if len(options) > 0 {
+		opt = options[0]
+	}
+
+	if len(opt.Section) == 0 {
+		opt.Section = "i18n"
+	}
+	sec := macaron.Config().Section(opt.Section)
+
+	opt.SubURL = strings.TrimSuffix(opt.SubURL, "/")
+
+	if len(opt.Langs) == 0 {
+		opt.Langs = sec.Key("LANGS").Strings(",")
+	}
+	if len(opt.Names) == 0 {
+		opt.Names = sec.Key("NAMES").Strings(",")
+	}
+	if len(opt.Langs) == 0 {
+		panic("no language is specified")
+	} else if len(opt.Langs) != len(opt.Names) {
+		panic("length of langs is not same as length of names")
+	}
+	i18n.SetDefaultLang(opt.DefaultLang)
+
+	if len(opt.Directory) == 0 {
+		opt.Directory = sec.Key("DIRECTORY").MustString("conf/locale")
+	}
+	if len(opt.CustomDirectory) == 0 {
+		opt.CustomDirectory = sec.Key("CUSTOM_DIRECTORY").MustString("custom/conf/locale")
+	}
+	if len(opt.Format) == 0 {
+		opt.Format = sec.Key("FORMAT").MustString("locale_%s.ini")
+	}
+	if len(opt.Parameter) == 0 {
+		opt.Parameter = sec.Key("PARAMETER").MustString("lang")
+	}
+	if !opt.Redirect {
+		opt.Redirect = sec.Key("REDIRECT").MustBool()
+	}
+	if len(opt.TmplName) == 0 {
+		opt.TmplName = sec.Key("TMPL_NAME").MustString("i18n")
+	}
+
+	return opt
+}
+
+type LangType struct {
+	Lang, Name string
+}
+
+// I18n is a middleware provides localization layer for your application.
+// Paramenter langs must be in the form of "en-US", "zh-CN", etc.
+// Otherwise it may not recognize browser input.
+func I18n(options ...Options) macaron.Handler {
+	opt := prepareOptions(options)
+	m := initLocales(opt)
+	return func(ctx *macaron.Context) {
+		isNeedRedir := false
+		hasCookie := false
+
+		// 1. Check URL arguments.
+		lang := ctx.Query(opt.Parameter)
+
+		// 2. Get language information from cookies.
+		if len(lang) == 0 {
+			lang = ctx.GetCookie("lang")
+			hasCookie = true
+		} else {
+			isNeedRedir = true
+		}
+
+		// Check again in case someone modify by purpose.
+		if !i18n.IsExist(lang) {
+			lang = ""
+			isNeedRedir = false
+			hasCookie = false
+		}
+
+		// 3. Get language information from 'Accept-Language'.
+		// The first element in the list is chosen to be the default language automatically.
+		if len(lang) == 0 {
+			tags, _, _ := language.ParseAcceptLanguage(ctx.Req.Header.Get("Accept-Language"))
+			tag, _, _ := m.Match(tags...)
+			lang = tag.String()
+			isNeedRedir = false
+		}
+
+		curLang := LangType{
+			Lang: lang,
+		}
+
+		// Save language information in cookies.
+		if !hasCookie {
+			ctx.SetCookie("lang", curLang.Lang, 1<<31-1, "/"+strings.TrimPrefix(opt.SubURL, "/"))
+		}
+
+		restLangs := make([]LangType, 0, i18n.Count()-1)
+		langs := i18n.ListLangs()
+		names := i18n.ListLangDescs()
+		for i, v := range langs {
+			if lang != v {
+				restLangs = append(restLangs, LangType{v, names[i]})
+			} else {
+				curLang.Name = names[i]
+			}
+		}
+
+		// Set language properties.
+		locale := Locale{i18n.Locale{lang}}
+		ctx.Map(locale)
+		ctx.Locale = locale
+		ctx.Data[opt.TmplName] = locale
+		ctx.Data["Tr"] = i18n.Tr
+		ctx.Data["Lang"] = locale.Lang
+		ctx.Data["LangName"] = curLang.Name
+		ctx.Data["AllLangs"] = append([]LangType{curLang}, restLangs...)
+		ctx.Data["RestLangs"] = restLangs
+
+		if opt.Redirect && isNeedRedir {
+			ctx.Redirect(opt.SubURL + ctx.Req.RequestURI[:strings.Index(ctx.Req.RequestURI, "?")])
+		}
+	}
+}

+ 191 - 0
vendor/github.com/go-macaron/inject/LICENSE

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

+ 11 - 0
vendor/github.com/go-macaron/inject/README.md

@@ -0,0 +1,11 @@
+# inject [![Build Status](https://travis-ci.org/go-macaron/inject.svg?branch=master)](https://travis-ci.org/go-macaron/inject) [![](http://gocover.io/_badge/github.com/go-macaron/inject)](http://gocover.io/github.com/go-macaron/inject)
+
+Package inject provides utilities for mapping and injecting dependencies in various ways.
+
+**This a modified version of [codegangsta/inject](https://github.com/codegangsta/inject) for special purpose of Macaron**
+
+**Please use the original version if you need dependency injection feature**
+
+## License
+
+This project is under the Apache License, Version 2.0. See the [LICENSE](LICENSE) file for the full license text.

+ 262 - 0
vendor/github.com/go-macaron/inject/inject.go

@@ -0,0 +1,262 @@
+// Copyright 2013 Jeremy Saenz
+// Copyright 2015 The Macaron Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+// Package inject provides utilities for mapping and injecting dependencies in various ways.
+package inject
+
+import (
+	"fmt"
+	"reflect"
+)
+
+// Injector represents an interface for mapping and injecting dependencies into structs
+// and function arguments.
+type Injector interface {
+	Applicator
+	Invoker
+	TypeMapper
+	// SetParent sets the parent of the injector. If the injector cannot find a
+	// dependency in its Type map it will check its parent before returning an
+	// error.
+	SetParent(Injector)
+}
+
+// Applicator represents an interface for mapping dependencies to a struct.
+type Applicator interface {
+	// Maps dependencies in the Type map to each field in the struct
+	// that is tagged with 'inject'. Returns an error if the injection
+	// fails.
+	Apply(interface{}) error
+}
+
+// Invoker represents an interface for calling functions via reflection.
+type Invoker interface {
+	// Invoke attempts to call the interface{} provided as a function,
+	// providing dependencies for function arguments based on Type. Returns
+	// a slice of reflect.Value representing the returned values of the function.
+	// Returns an error if the injection fails.
+	Invoke(interface{}) ([]reflect.Value, error)
+}
+
+// FastInvoker represents an interface in order to avoid the calling function via reflection.
+//
+// example:
+//	type handlerFuncHandler func(http.ResponseWriter, *http.Request) error
+//	func (f handlerFuncHandler)Invoke([]interface{}) ([]reflect.Value, error){
+//		ret := f(p[0].(http.ResponseWriter), p[1].(*http.Request))
+//		return []reflect.Value{reflect.ValueOf(ret)}, nil
+//	}
+//
+//	type funcHandler func(int, string)
+//	func (f funcHandler)Invoke([]interface{}) ([]reflect.Value, error){
+//		f(p[0].(int), p[1].(string))
+//		return nil, nil
+//	}
+type FastInvoker interface {
+	// Invoke attempts to call the ordinary functions. If f is a function
+	// with the appropriate signature, f.Invoke([]interface{}) is a Call that calls f.
+	// Returns a slice of reflect.Value representing the returned values of the function.
+	// Returns an error if the injection fails.
+	Invoke([]interface{}) ([]reflect.Value, error)
+}
+
+// IsFastInvoker check interface is FastInvoker
+func IsFastInvoker(h interface{}) bool {
+	_, ok := h.(FastInvoker)
+	return ok
+}
+
+// TypeMapper represents an interface for mapping interface{} values based on type.
+type TypeMapper interface {
+	// Maps the interface{} value based on its immediate type from reflect.TypeOf.
+	Map(interface{}) TypeMapper
+	// Maps the interface{} value based on the pointer of an Interface provided.
+	// This is really only useful for mapping a value as an interface, as interfaces
+	// cannot at this time be referenced directly without a pointer.
+	MapTo(interface{}, interface{}) TypeMapper
+	// Provides a possibility to directly insert a mapping based on type and value.
+	// This makes it possible to directly map type arguments not possible to instantiate
+	// with reflect like unidirectional channels.
+	Set(reflect.Type, reflect.Value) TypeMapper
+	// Returns the Value that is mapped to the current type. Returns a zeroed Value if
+	// the Type has not been mapped.
+	GetVal(reflect.Type) reflect.Value
+}
+
+type injector struct {
+	values map[reflect.Type]reflect.Value
+	parent Injector
+}
+
+// InterfaceOf dereferences a pointer to an Interface type.
+// It panics if value is not an pointer to an interface.
+func InterfaceOf(value interface{}) reflect.Type {
+	t := reflect.TypeOf(value)
+
+	for t.Kind() == reflect.Ptr {
+		t = t.Elem()
+	}
+
+	if t.Kind() != reflect.Interface {
+		panic("Called inject.InterfaceOf with a value that is not a pointer to an interface. (*MyInterface)(nil)")
+	}
+
+	return t
+}
+
+// New returns a new Injector.
+func New() Injector {
+	return &injector{
+		values: make(map[reflect.Type]reflect.Value),
+	}
+}
+
+// Invoke attempts to call the interface{} provided as a function,
+// providing dependencies for function arguments based on Type.
+// Returns a slice of reflect.Value representing the returned values of the function.
+// Returns an error if the injection fails.
+// It panics if f is not a function
+func (inj *injector) Invoke(f interface{}) ([]reflect.Value, error) {
+	t := reflect.TypeOf(f)
+	switch v := f.(type) {
+	case FastInvoker:
+		return inj.fastInvoke(v, t, t.NumIn())
+	default:
+		return inj.callInvoke(f, t, t.NumIn())
+	}
+}
+
+func (inj *injector) fastInvoke(f FastInvoker, t reflect.Type, numIn int) ([]reflect.Value, error) {
+	var in []interface{}
+	if numIn > 0 {
+		in = make([]interface{}, numIn) // Panic if t is not kind of Func
+		var argType reflect.Type
+		var val reflect.Value
+		for i := 0; i < numIn; i++ {
+			argType = t.In(i)
+			val = inj.GetVal(argType)
+			if !val.IsValid() {
+				return nil, fmt.Errorf("Value not found for type %v", argType)
+			}
+
+			in[i] = val.Interface()
+		}
+	}
+	return f.Invoke(in)
+}
+
+// callInvoke reflect.Value.Call
+func (inj *injector) callInvoke(f interface{}, t reflect.Type, numIn int) ([]reflect.Value, error) {
+	var in []reflect.Value
+	if numIn > 0 {
+		in = make([]reflect.Value, numIn)
+		var argType reflect.Type
+		var val reflect.Value
+		for i := 0; i < numIn; i++ {
+			argType = t.In(i)
+			val = inj.GetVal(argType)
+			if !val.IsValid() {
+				return nil, fmt.Errorf("Value not found for type %v", argType)
+			}
+
+			in[i] = val
+		}
+	}
+	return reflect.ValueOf(f).Call(in), nil
+}
+
+// Maps dependencies in the Type map to each field in the struct
+// that is tagged with 'inject'.
+// Returns an error if the injection fails.
+func (inj *injector) Apply(val interface{}) error {
+	v := reflect.ValueOf(val)
+
+	for v.Kind() == reflect.Ptr {
+		v = v.Elem()
+	}
+
+	if v.Kind() != reflect.Struct {
+		return nil // Should not panic here ?
+	}
+
+	t := v.Type()
+
+	for i := 0; i < v.NumField(); i++ {
+		f := v.Field(i)
+		structField := t.Field(i)
+		if f.CanSet() && (structField.Tag == "inject" || structField.Tag.Get("inject") != "") {
+			ft := f.Type()
+			v := inj.GetVal(ft)
+			if !v.IsValid() {
+				return fmt.Errorf("Value not found for type %v", ft)
+			}
+
+			f.Set(v)
+		}
+
+	}
+
+	return nil
+}
+
+// Maps the concrete value of val to its dynamic type using reflect.TypeOf,
+// It returns the TypeMapper registered in.
+func (i *injector) Map(val interface{}) TypeMapper {
+	i.values[reflect.TypeOf(val)] = reflect.ValueOf(val)
+	return i
+}
+
+func (i *injector) MapTo(val interface{}, ifacePtr interface{}) TypeMapper {
+	i.values[InterfaceOf(ifacePtr)] = reflect.ValueOf(val)
+	return i
+}
+
+// Maps the given reflect.Type to the given reflect.Value and returns
+// the Typemapper the mapping has been registered in.
+func (i *injector) Set(typ reflect.Type, val reflect.Value) TypeMapper {
+	i.values[typ] = val
+	return i
+}
+
+func (i *injector) GetVal(t reflect.Type) reflect.Value {
+	val := i.values[t]
+
+	if val.IsValid() {
+		return val
+	}
+
+	// no concrete types found, try to find implementors
+	// if t is an interface
+	if t.Kind() == reflect.Interface {
+		for k, v := range i.values {
+			if k.Implements(t) {
+				val = v
+				break
+			}
+		}
+	}
+
+	// Still no type found, try to look it up on the parent
+	if !val.IsValid() && i.parent != nil {
+		val = i.parent.GetVal(t)
+	}
+
+	return val
+
+}
+
+func (i *injector) SetParent(parent Injector) {
+	i.parent = parent
+}

+ 191 - 0
vendor/github.com/go-macaron/session/LICENSE

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

+ 20 - 0
vendor/github.com/go-macaron/session/README.md

@@ -0,0 +1,20 @@
+# session [![Build Status](https://travis-ci.org/go-macaron/session.svg?branch=master)](https://travis-ci.org/go-macaron/session) [![](http://gocover.io/_badge/github.com/go-macaron/session)](http://gocover.io/github.com/go-macaron/session)
+
+Middleware session provides session management for [Macaron](https://github.com/go-macaron/macaron). It can use many session providers, including memory, file, Redis, Memcache, PostgreSQL, MySQL, Couchbase, Ledis and Nodb.
+
+### Installation
+
+	go get github.com/go-macaron/session
+	
+## Getting Help
+
+- [API Reference](https://gowalker.org/github.com/go-macaron/session)
+- [Documentation](http://go-macaron.com/docs/middlewares/session)
+
+## Credits
+
+This package is a modified version of [beego/session](https://github.com/astaxie/beego/tree/master/session).
+
+## License
+
+This project is under the Apache License, Version 2.0. See the [LICENSE](LICENSE) file for the full license text.

+ 261 - 0
vendor/github.com/go-macaron/session/file.go

@@ -0,0 +1,261 @@
+// Copyright 2013 Beego Authors
+// Copyright 2014 The Macaron Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package session
+
+import (
+	"fmt"
+	"io/ioutil"
+	"log"
+	"os"
+	"path"
+	"path/filepath"
+	"sync"
+	"time"
+
+	"github.com/Unknwon/com"
+)
+
+// FileStore represents a file session store implementation.
+type FileStore struct {
+	p    *FileProvider
+	sid  string
+	lock sync.RWMutex
+	data map[interface{}]interface{}
+}
+
+// NewFileStore creates and returns a file session store.
+func NewFileStore(p *FileProvider, sid string, kv map[interface{}]interface{}) *FileStore {
+	return &FileStore{
+		p:    p,
+		sid:  sid,
+		data: kv,
+	}
+}
+
+// Set sets value to given key in session.
+func (s *FileStore) Set(key, val interface{}) error {
+	s.lock.Lock()
+	defer s.lock.Unlock()
+
+	s.data[key] = val
+	return nil
+}
+
+// Get gets value by given key in session.
+func (s *FileStore) Get(key interface{}) interface{} {
+	s.lock.RLock()
+	defer s.lock.RUnlock()
+
+	return s.data[key]
+}
+
+// Delete delete a key from session.
+func (s *FileStore) Delete(key interface{}) error {
+	s.lock.Lock()
+	defer s.lock.Unlock()
+
+	delete(s.data, key)
+	return nil
+}
+
+// ID returns current session ID.
+func (s *FileStore) ID() string {
+	return s.sid
+}
+
+// Release releases resource and save data to provider.
+func (s *FileStore) Release() error {
+	s.p.lock.Lock()
+	defer s.p.lock.Unlock()
+
+	data, err := EncodeGob(s.data)
+	if err != nil {
+		return err
+	}
+
+	return ioutil.WriteFile(s.p.filepath(s.sid), data, os.ModePerm)
+}
+
+// Flush deletes all session data.
+func (s *FileStore) Flush() error {
+	s.lock.Lock()
+	defer s.lock.Unlock()
+
+	s.data = make(map[interface{}]interface{})
+	return nil
+}
+
+// FileProvider represents a file session provider implementation.
+type FileProvider struct {
+	lock        sync.RWMutex
+	maxlifetime int64
+	rootPath    string
+}
+
+// Init initializes file session provider with given root path.
+func (p *FileProvider) Init(maxlifetime int64, rootPath string) error {
+	p.lock.Lock()
+	p.maxlifetime = maxlifetime
+	p.rootPath = rootPath
+	p.lock.Unlock()
+	return nil
+}
+
+func (p *FileProvider) filepath(sid string) string {
+	return path.Join(p.rootPath, string(sid[0]), string(sid[1]), sid)
+}
+
+// Read returns raw session store by session ID.
+func (p *FileProvider) Read(sid string) (_ RawStore, err error) {
+	filename := p.filepath(sid)
+	if err = os.MkdirAll(path.Dir(filename), os.ModePerm); err != nil {
+		return nil, err
+	}
+	p.lock.RLock()
+	defer p.lock.RUnlock()
+
+	var f *os.File
+	if com.IsFile(filename) {
+		f, err = os.OpenFile(filename, os.O_RDWR, os.ModePerm)
+	} else {
+		f, err = os.Create(filename)
+	}
+	if err != nil {
+		return nil, err
+	}
+	defer f.Close()
+
+	if err = os.Chtimes(filename, time.Now(), time.Now()); err != nil {
+		return nil, err
+	}
+
+	var kv map[interface{}]interface{}
+	data, err := ioutil.ReadAll(f)
+	if err != nil {
+		return nil, err
+	}
+	if len(data) == 0 {
+		kv = make(map[interface{}]interface{})
+	} else {
+		kv, err = DecodeGob(data)
+		if err != nil {
+			return nil, err
+		}
+	}
+	return NewFileStore(p, sid, kv), nil
+}
+
+// Exist returns true if session with given ID exists.
+func (p *FileProvider) Exist(sid string) bool {
+	p.lock.RLock()
+	defer p.lock.RUnlock()
+	return com.IsFile(p.filepath(sid))
+}
+
+// Destory deletes a session by session ID.
+func (p *FileProvider) Destory(sid string) error {
+	p.lock.Lock()
+	defer p.lock.Unlock()
+	return os.Remove(p.filepath(sid))
+}
+
+func (p *FileProvider) regenerate(oldsid, sid string) (err error) {
+	p.lock.Lock()
+	defer p.lock.Unlock()
+
+	filename := p.filepath(sid)
+	if com.IsExist(filename) {
+		return fmt.Errorf("new sid '%s' already exists", sid)
+	}
+
+	oldname := p.filepath(oldsid)
+	if !com.IsFile(oldname) {
+		data, err := EncodeGob(make(map[interface{}]interface{}))
+		if err != nil {
+			return err
+		}
+		if err = os.MkdirAll(path.Dir(oldname), os.ModePerm); err != nil {
+			return err
+		}
+		if err = ioutil.WriteFile(oldname, data, os.ModePerm); err != nil {
+			return err
+		}
+	}
+
+	if err = os.MkdirAll(path.Dir(filename), os.ModePerm); err != nil {
+		return err
+	}
+	if err = os.Rename(oldname, filename); err != nil {
+		return err
+	}
+	return nil
+}
+
+// Regenerate regenerates a session store from old session ID to new one.
+func (p *FileProvider) Regenerate(oldsid, sid string) (_ RawStore, err error) {
+	if err := p.regenerate(oldsid, sid); err != nil {
+		return nil, err
+	}
+
+	return p.Read(sid)
+}
+
+// Count counts and returns number of sessions.
+func (p *FileProvider) Count() int {
+	count := 0
+	if err := filepath.Walk(p.rootPath, func(path string, fi os.FileInfo, err error) error {
+		if err != nil {
+			return err
+		}
+
+		if !fi.IsDir() {
+			count++
+		}
+		return nil
+	}); err != nil {
+		log.Printf("error counting session files: %v", err)
+		return 0
+	}
+	return count
+}
+
+// GC calls GC to clean expired sessions.
+func (p *FileProvider) GC() {
+	p.lock.RLock()
+	defer p.lock.RUnlock()
+
+	if !com.IsExist(p.rootPath) {
+		return
+	}
+
+	if err := filepath.Walk(p.rootPath, func(path string, fi os.FileInfo, err error) error {
+		if err != nil {
+			return err
+		}
+
+		if !fi.IsDir() &&
+			(fi.ModTime().Unix()+p.maxlifetime) < time.Now().Unix() {
+			return os.Remove(path)
+		}
+		return nil
+	}); err != nil {
+		log.Printf("error garbage collecting session files: %v", err)
+	}
+}
+
+func init() {
+	Register("file", &FileProvider{})
+}

+ 217 - 0
vendor/github.com/go-macaron/session/memory.go

@@ -0,0 +1,217 @@
+// Copyright 2013 Beego Authors
+// Copyright 2014 The Macaron Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package session
+
+import (
+	"container/list"
+	"fmt"
+	"sync"
+	"time"
+)
+
+// MemStore represents a in-memory session store implementation.
+type MemStore struct {
+	sid        string
+	lock       sync.RWMutex
+	data       map[interface{}]interface{}
+	lastAccess time.Time
+}
+
+// NewMemStore creates and returns a memory session store.
+func NewMemStore(sid string) *MemStore {
+	return &MemStore{
+		sid:        sid,
+		data:       make(map[interface{}]interface{}),
+		lastAccess: time.Now(),
+	}
+}
+
+// Set sets value to given key in session.
+func (s *MemStore) Set(key, val interface{}) error {
+	s.lock.Lock()
+	defer s.lock.Unlock()
+
+	s.data[key] = val
+	return nil
+}
+
+// Get gets value by given key in session.
+func (s *MemStore) Get(key interface{}) interface{} {
+	s.lock.RLock()
+	defer s.lock.RUnlock()
+
+	return s.data[key]
+}
+
+// Delete deletes a key from session.
+func (s *MemStore) Delete(key interface{}) error {
+	s.lock.Lock()
+	defer s.lock.Unlock()
+
+	delete(s.data, key)
+	return nil
+}
+
+// ID returns current session ID.
+func (s *MemStore) ID() string {
+	return s.sid
+}
+
+// Release releases resource and save data to provider.
+func (_ *MemStore) Release() error {
+	return nil
+}
+
+// Flush deletes all session data.
+func (s *MemStore) Flush() error {
+	s.lock.Lock()
+	defer s.lock.Unlock()
+
+	s.data = make(map[interface{}]interface{})
+	return nil
+}
+
+// MemProvider represents a in-memory session provider implementation.
+type MemProvider struct {
+	lock        sync.RWMutex
+	maxLifetime int64
+	data        map[string]*list.Element
+	// A priority list whose lastAccess newer gets higer priority.
+	list *list.List
+}
+
+// Init initializes memory session provider.
+func (p *MemProvider) Init(maxLifetime int64, _ string) error {
+	p.lock.Lock()
+	p.maxLifetime = maxLifetime
+	p.lock.Unlock()
+	return nil
+}
+
+// update expands time of session store by given ID.
+func (p *MemProvider) update(sid string) error {
+	p.lock.Lock()
+	defer p.lock.Unlock()
+
+	if e, ok := p.data[sid]; ok {
+		e.Value.(*MemStore).lastAccess = time.Now()
+		p.list.MoveToFront(e)
+		return nil
+	}
+	return nil
+}
+
+// Read returns raw session store by session ID.
+func (p *MemProvider) Read(sid string) (_ RawStore, err error) {
+	p.lock.RLock()
+	e, ok := p.data[sid]
+	p.lock.RUnlock()
+
+	if ok {
+		if err = p.update(sid); err != nil {
+			return nil, err
+		}
+		return e.Value.(*MemStore), nil
+	}
+
+	// Create a new session.
+	p.lock.Lock()
+	defer p.lock.Unlock()
+
+	s := NewMemStore(sid)
+	p.data[sid] = p.list.PushBack(s)
+	return s, nil
+}
+
+// Exist returns true if session with given ID exists.
+func (p *MemProvider) Exist(sid string) bool {
+	p.lock.RLock()
+	defer p.lock.RUnlock()
+
+	_, ok := p.data[sid]
+	return ok
+}
+
+// Destory deletes a session by session ID.
+func (p *MemProvider) Destory(sid string) error {
+	p.lock.Lock()
+	defer p.lock.Unlock()
+
+	e, ok := p.data[sid]
+	if !ok {
+		return nil
+	}
+
+	p.list.Remove(e)
+	delete(p.data, sid)
+	return nil
+}
+
+// Regenerate regenerates a session store from old session ID to new one.
+func (p *MemProvider) Regenerate(oldsid, sid string) (RawStore, error) {
+	if p.Exist(sid) {
+		return nil, fmt.Errorf("new sid '%s' already exists", sid)
+	}
+
+	s, err := p.Read(oldsid)
+	if err != nil {
+		return nil, err
+	}
+
+	if err = p.Destory(oldsid); err != nil {
+		return nil, err
+	}
+
+	s.(*MemStore).sid = sid
+
+	p.lock.Lock()
+	defer p.lock.Unlock()
+	p.data[sid] = p.list.PushBack(s)
+	return s, nil
+}
+
+// Count counts and returns number of sessions.
+func (p *MemProvider) Count() int {
+	return p.list.Len()
+}
+
+// GC calls GC to clean expired sessions.
+func (p *MemProvider) GC() {
+	p.lock.RLock()
+	for {
+		// No session in the list.
+		e := p.list.Back()
+		if e == nil {
+			break
+		}
+
+		if (e.Value.(*MemStore).lastAccess.Unix() + p.maxLifetime) < time.Now().Unix() {
+			p.lock.RUnlock()
+			p.lock.Lock()
+			p.list.Remove(e)
+			delete(p.data, e.Value.(*MemStore).sid)
+			p.lock.Unlock()
+			p.lock.RLock()
+		} else {
+			break
+		}
+	}
+	p.lock.RUnlock()
+}
+
+func init() {
+	Register("memory", &MemProvider{list: list.New(), data: make(map[string]*list.Element)})
+}

+ 235 - 0
vendor/github.com/go-macaron/session/redis/redis.go

@@ -0,0 +1,235 @@
+// Copyright 2013 Beego Authors
+// Copyright 2014 The Macaron Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package session
+
+import (
+	"fmt"
+	"strings"
+	"sync"
+	"time"
+
+	"github.com/Unknwon/com"
+	"gopkg.in/ini.v1"
+	"gopkg.in/redis.v2"
+
+	"github.com/go-macaron/session"
+)
+
+// RedisStore represents a redis session store implementation.
+type RedisStore struct {
+	c           *redis.Client
+	prefix, sid string
+	duration    time.Duration
+	lock        sync.RWMutex
+	data        map[interface{}]interface{}
+}
+
+// NewRedisStore creates and returns a redis session store.
+func NewRedisStore(c *redis.Client, prefix, sid string, dur time.Duration, kv map[interface{}]interface{}) *RedisStore {
+	return &RedisStore{
+		c:        c,
+		prefix:   prefix,
+		sid:      sid,
+		duration: dur,
+		data:     kv,
+	}
+}
+
+// Set sets value to given key in session.
+func (s *RedisStore) Set(key, val interface{}) error {
+	s.lock.Lock()
+	defer s.lock.Unlock()
+
+	s.data[key] = val
+	return nil
+}
+
+// Get gets value by given key in session.
+func (s *RedisStore) Get(key interface{}) interface{} {
+	s.lock.RLock()
+	defer s.lock.RUnlock()
+
+	return s.data[key]
+}
+
+// Delete delete a key from session.
+func (s *RedisStore) Delete(key interface{}) error {
+	s.lock.Lock()
+	defer s.lock.Unlock()
+
+	delete(s.data, key)
+	return nil
+}
+
+// ID returns current session ID.
+func (s *RedisStore) ID() string {
+	return s.sid
+}
+
+// Release releases resource and save data to provider.
+func (s *RedisStore) Release() error {
+	data, err := session.EncodeGob(s.data)
+	if err != nil {
+		return err
+	}
+
+	return s.c.SetEx(s.prefix+s.sid, s.duration, string(data)).Err()
+}
+
+// Flush deletes all session data.
+func (s *RedisStore) Flush() error {
+	s.lock.Lock()
+	defer s.lock.Unlock()
+
+	s.data = make(map[interface{}]interface{})
+	return nil
+}
+
+// RedisProvider represents a redis session provider implementation.
+type RedisProvider struct {
+	c        *redis.Client
+	duration time.Duration
+	prefix   string
+}
+
+// Init initializes redis session provider.
+// configs: network=tcp,addr=:6379,password=macaron,db=0,pool_size=100,idle_timeout=180,prefix=session;
+func (p *RedisProvider) Init(maxlifetime int64, configs string) (err error) {
+	p.duration, err = time.ParseDuration(fmt.Sprintf("%ds", maxlifetime))
+	if err != nil {
+		return err
+	}
+
+	cfg, err := ini.Load([]byte(strings.Replace(configs, ",", "\n", -1)))
+	if err != nil {
+		return err
+	}
+
+	opt := &redis.Options{
+		Network: "tcp",
+	}
+	for k, v := range cfg.Section("").KeysHash() {
+		switch k {
+		case "network":
+			opt.Network = v
+		case "addr":
+			opt.Addr = v
+		case "password":
+			opt.Password = v
+		case "db":
+			opt.DB = com.StrTo(v).MustInt64()
+		case "pool_size":
+			opt.PoolSize = com.StrTo(v).MustInt()
+		case "idle_timeout":
+			opt.IdleTimeout, err = time.ParseDuration(v + "s")
+			if err != nil {
+				return fmt.Errorf("error parsing idle timeout: %v", err)
+			}
+		case "prefix":
+			p.prefix = v
+		default:
+			return fmt.Errorf("session/redis: unsupported option '%s'", k)
+		}
+	}
+
+	p.c = redis.NewClient(opt)
+	return p.c.Ping().Err()
+}
+
+// Read returns raw session store by session ID.
+func (p *RedisProvider) Read(sid string) (session.RawStore, error) {
+	psid := p.prefix + sid
+	if !p.Exist(sid) {
+		if err := p.c.Set(psid, "").Err(); err != nil {
+			return nil, err
+		}
+	}
+
+	var kv map[interface{}]interface{}
+	kvs, err := p.c.Get(psid).Result()
+	if err != nil {
+		return nil, err
+	}
+	if len(kvs) == 0 {
+		kv = make(map[interface{}]interface{})
+	} else {
+		kv, err = session.DecodeGob([]byte(kvs))
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	return NewRedisStore(p.c, p.prefix, sid, p.duration, kv), nil
+}
+
+// Exist returns true if session with given ID exists.
+func (p *RedisProvider) Exist(sid string) bool {
+	has, err := p.c.Exists(p.prefix + sid).Result()
+	return err == nil && has
+}
+
+// Destory deletes a session by session ID.
+func (p *RedisProvider) Destory(sid string) error {
+	return p.c.Del(p.prefix + sid).Err()
+}
+
+// Regenerate regenerates a session store from old session ID to new one.
+func (p *RedisProvider) Regenerate(oldsid, sid string) (_ session.RawStore, err error) {
+	poldsid := p.prefix + oldsid
+	psid := p.prefix + sid
+
+	if p.Exist(sid) {
+		return nil, fmt.Errorf("new sid '%s' already exists", sid)
+	} else if !p.Exist(oldsid) {
+		// Make a fake old session.
+		if err = p.c.SetEx(poldsid, p.duration, "").Err(); err != nil {
+			return nil, err
+		}
+	}
+
+	if err = p.c.Rename(poldsid, psid).Err(); err != nil {
+		return nil, err
+	}
+
+	var kv map[interface{}]interface{}
+	kvs, err := p.c.Get(psid).Result()
+	if err != nil {
+		return nil, err
+	}
+
+	if len(kvs) == 0 {
+		kv = make(map[interface{}]interface{})
+	} else {
+		kv, err = session.DecodeGob([]byte(kvs))
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	return NewRedisStore(p.c, p.prefix, sid, p.duration, kv), nil
+}
+
+// Count counts and returns number of sessions.
+func (p *RedisProvider) Count() int {
+	return int(p.c.DbSize().Val())
+}
+
+// GC calls GC to clean expired sessions.
+func (_ *RedisProvider) GC() {}
+
+func init() {
+	session.Register("redis", &RedisProvider{})
+}

+ 1 - 0
vendor/github.com/go-macaron/session/redis/redis.goconvey

@@ -0,0 +1 @@
+ignore

+ 399 - 0
vendor/github.com/go-macaron/session/session.go

@@ -0,0 +1,399 @@
+// Copyright 2013 Beego Authors
+// Copyright 2014 The Macaron Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+// Package session a middleware that provides the session management of Macaron.
+package session
+
+import (
+	"encoding/hex"
+	"fmt"
+	"net/http"
+	"net/url"
+	"time"
+
+	"gopkg.in/macaron.v1"
+)
+
+const _VERSION = "0.3.0"
+
+func Version() string {
+	return _VERSION
+}
+
+// RawStore is the interface that operates the session data.
+type RawStore interface {
+	// Set sets value to given key in session.
+	Set(interface{}, interface{}) error
+	// Get gets value by given key in session.
+	Get(interface{}) interface{}
+	// Delete deletes a key from session.
+	Delete(interface{}) error
+	// ID returns current session ID.
+	ID() string
+	// Release releases session resource and save data to provider.
+	Release() error
+	// Flush deletes all session data.
+	Flush() error
+}
+
+// Store is the interface that contains all data for one session process with specific ID.
+type Store interface {
+	RawStore
+	// Read returns raw session store by session ID.
+	Read(string) (RawStore, error)
+	// Destory deletes a session.
+	Destory(*macaron.Context) error
+	// RegenerateId regenerates a session store from old session ID to new one.
+	RegenerateId(*macaron.Context) (RawStore, error)
+	// Count counts and returns number of sessions.
+	Count() int
+	// GC calls GC to clean expired sessions.
+	GC()
+}
+
+type store struct {
+	RawStore
+	*Manager
+}
+
+var _ Store = &store{}
+
+// Options represents a struct for specifying configuration options for the session middleware.
+type Options struct {
+	// Name of provider. Default is "memory".
+	Provider string
+	// Provider configuration, it's corresponding to provider.
+	ProviderConfig string
+	// Cookie name to save session ID. Default is "MacaronSession".
+	CookieName string
+	// Cookie path to store. Default is "/".
+	CookiePath string
+	// GC interval time in seconds. Default is 3600.
+	Gclifetime int64
+	// Max life time in seconds. Default is whatever GC interval time is.
+	Maxlifetime int64
+	// Use HTTPS only. Default is false.
+	Secure bool
+	// Cookie life time. Default is 0.
+	CookieLifeTime int
+	// Cookie domain name. Default is empty.
+	Domain string
+	// Session ID length. Default is 16.
+	IDLength int
+	// Configuration section name. Default is "session".
+	Section string
+}
+
+func prepareOptions(options []Options) Options {
+	var opt Options
+	if len(options) > 0 {
+		opt = options[0]
+	}
+	if len(opt.Section) == 0 {
+		opt.Section = "session"
+	}
+	sec := macaron.Config().Section(opt.Section)
+
+	if len(opt.Provider) == 0 {
+		opt.Provider = sec.Key("PROVIDER").MustString("memory")
+	}
+	if len(opt.ProviderConfig) == 0 {
+		opt.ProviderConfig = sec.Key("PROVIDER_CONFIG").MustString("data/sessions")
+	}
+	if len(opt.CookieName) == 0 {
+		opt.CookieName = sec.Key("COOKIE_NAME").MustString("MacaronSession")
+	}
+	if len(opt.CookiePath) == 0 {
+		opt.CookiePath = sec.Key("COOKIE_PATH").MustString("/")
+	}
+	if opt.Gclifetime == 0 {
+		opt.Gclifetime = sec.Key("GC_INTERVAL_TIME").MustInt64(3600)
+	}
+	if opt.Maxlifetime == 0 {
+		opt.Maxlifetime = sec.Key("MAX_LIFE_TIME").MustInt64(opt.Gclifetime)
+	}
+	if !opt.Secure {
+		opt.Secure = sec.Key("SECURE").MustBool()
+	}
+	if opt.CookieLifeTime == 0 {
+		opt.CookieLifeTime = sec.Key("COOKIE_LIFE_TIME").MustInt()
+	}
+	if len(opt.Domain) == 0 {
+		opt.Domain = sec.Key("DOMAIN").String()
+	}
+	if opt.IDLength == 0 {
+		opt.IDLength = sec.Key("ID_LENGTH").MustInt(16)
+	}
+
+	return opt
+}
+
+// Sessioner is a middleware that maps a session.SessionStore service into the Macaron handler chain.
+// An single variadic session.Options struct can be optionally provided to configure.
+func Sessioner(options ...Options) macaron.Handler {
+	opt := prepareOptions(options)
+	manager, err := NewManager(opt.Provider, opt)
+	if err != nil {
+		panic(err)
+	}
+	go manager.startGC()
+
+	return func(ctx *macaron.Context) {
+		sess, err := manager.Start(ctx)
+		if err != nil {
+			panic("session(start): " + err.Error())
+		}
+
+		// Get flash.
+		vals, _ := url.ParseQuery(ctx.GetCookie("macaron_flash"))
+		if len(vals) > 0 {
+			f := &Flash{Values: vals}
+			f.ErrorMsg = f.Get("error")
+			f.SuccessMsg = f.Get("success")
+			f.InfoMsg = f.Get("info")
+			f.WarningMsg = f.Get("warning")
+			ctx.Data["Flash"] = f
+			ctx.SetCookie("macaron_flash", "", -1, opt.CookiePath)
+		}
+
+		f := &Flash{ctx, url.Values{}, "", "", "", ""}
+		ctx.Resp.Before(func(macaron.ResponseWriter) {
+			if flash := f.Encode(); len(flash) > 0 {
+				ctx.SetCookie("macaron_flash", flash, 0, opt.CookiePath)
+			}
+		})
+
+		ctx.Map(f)
+		s := store{
+			RawStore: sess,
+			Manager:  manager,
+		}
+
+		ctx.MapTo(s, (*Store)(nil))
+
+		ctx.Next()
+
+		if err = sess.Release(); err != nil {
+			panic("session(release): " + err.Error())
+		}
+	}
+}
+
+// Provider is the interface that provides session manipulations.
+type Provider interface {
+	// Init initializes session provider.
+	Init(gclifetime int64, config string) error
+	// Read returns raw session store by session ID.
+	Read(sid string) (RawStore, error)
+	// Exist returns true if session with given ID exists.
+	Exist(sid string) bool
+	// Destory deletes a session by session ID.
+	Destory(sid string) error
+	// Regenerate regenerates a session store from old session ID to new one.
+	Regenerate(oldsid, sid string) (RawStore, error)
+	// Count counts and returns number of sessions.
+	Count() int
+	// GC calls GC to clean expired sessions.
+	GC()
+}
+
+var providers = make(map[string]Provider)
+
+// Register registers a provider.
+func Register(name string, provider Provider) {
+	if provider == nil {
+		panic("session: cannot register provider with nil value")
+	}
+	if _, dup := providers[name]; dup {
+		panic(fmt.Errorf("session: cannot register provider '%s' twice", name))
+	}
+	providers[name] = provider
+}
+
+//    _____
+//   /     \ _____    ____ _____     ____   ___________
+//  /  \ /  \\__  \  /    \\__  \   / ___\_/ __ \_  __ \
+// /    Y    \/ __ \|   |  \/ __ \_/ /_/  >  ___/|  | \/
+// \____|__  (____  /___|  (____  /\___  / \___  >__|
+//         \/     \/     \/     \//_____/      \/
+
+// Manager represents a struct that contains session provider and its configuration.
+type Manager struct {
+	provider Provider
+	opt      Options
+}
+
+// NewManager creates and returns a new session manager by given provider name and configuration.
+// It panics when given provider isn't registered.
+func NewManager(name string, opt Options) (*Manager, error) {
+	p, ok := providers[name]
+	if !ok {
+		return nil, fmt.Errorf("session: unknown provider '%s'(forgotten import?)", name)
+	}
+	return &Manager{p, opt}, p.Init(opt.Maxlifetime, opt.ProviderConfig)
+}
+
+// sessionId generates a new session ID with rand string, unix nano time, remote addr by hash function.
+func (m *Manager) sessionId() string {
+	return hex.EncodeToString(generateRandomKey(m.opt.IDLength / 2))
+}
+
+// Start starts a session by generating new one
+// or retrieve existence one by reading session ID from HTTP request if it's valid.
+func (m *Manager) Start(ctx *macaron.Context) (RawStore, error) {
+	sid := ctx.GetCookie(m.opt.CookieName)
+	if len(sid) > 0 && m.provider.Exist(sid) {
+		return m.provider.Read(sid)
+	}
+
+	sid = m.sessionId()
+	sess, err := m.provider.Read(sid)
+	if err != nil {
+		return nil, err
+	}
+
+	cookie := &http.Cookie{
+		Name:     m.opt.CookieName,
+		Value:    sid,
+		Path:     m.opt.CookiePath,
+		HttpOnly: true,
+		Secure:   m.opt.Secure,
+		Domain:   m.opt.Domain,
+	}
+	if m.opt.CookieLifeTime >= 0 {
+		cookie.MaxAge = m.opt.CookieLifeTime
+	}
+	http.SetCookie(ctx.Resp, cookie)
+	ctx.Req.AddCookie(cookie)
+	return sess, nil
+}
+
+// Read returns raw session store by session ID.
+func (m *Manager) Read(sid string) (RawStore, error) {
+	return m.provider.Read(sid)
+}
+
+// Destory deletes a session by given ID.
+func (m *Manager) Destory(ctx *macaron.Context) error {
+	sid := ctx.GetCookie(m.opt.CookieName)
+	if len(sid) == 0 {
+		return nil
+	}
+
+	if err := m.provider.Destory(sid); err != nil {
+		return err
+	}
+	cookie := &http.Cookie{
+		Name:     m.opt.CookieName,
+		Path:     m.opt.CookiePath,
+		HttpOnly: true,
+		Expires:  time.Now(),
+		MaxAge:   -1,
+	}
+	http.SetCookie(ctx.Resp, cookie)
+	return nil
+}
+
+// RegenerateId regenerates a session store from old session ID to new one.
+func (m *Manager) RegenerateId(ctx *macaron.Context) (sess RawStore, err error) {
+	sid := m.sessionId()
+	oldsid := ctx.GetCookie(m.opt.CookieName)
+	sess, err = m.provider.Regenerate(oldsid, sid)
+	if err != nil {
+		return nil, err
+	}
+	ck := &http.Cookie{
+		Name:     m.opt.CookieName,
+		Value:    sid,
+		Path:     m.opt.CookiePath,
+		HttpOnly: true,
+		Secure:   m.opt.Secure,
+		Domain:   m.opt.Domain,
+	}
+	if m.opt.CookieLifeTime >= 0 {
+		ck.MaxAge = m.opt.CookieLifeTime
+	}
+	http.SetCookie(ctx.Resp, ck)
+	ctx.Req.AddCookie(ck)
+	return sess, nil
+}
+
+// Count counts and returns number of sessions.
+func (m *Manager) Count() int {
+	return m.provider.Count()
+}
+
+// GC starts GC job in a certain period.
+func (m *Manager) GC() {
+	m.provider.GC()
+}
+
+// startGC starts GC job in a certain period.
+func (m *Manager) startGC() {
+	m.GC()
+	time.AfterFunc(time.Duration(m.opt.Gclifetime)*time.Second, func() { m.startGC() })
+}
+
+// SetSecure indicates whether to set cookie with HTTPS or not.
+func (m *Manager) SetSecure(secure bool) {
+	m.opt.Secure = secure
+}
+
+// ___________.____       _____    _________ ___ ___
+// \_   _____/|    |     /  _  \  /   _____//   |   \
+//  |    __)  |    |    /  /_\  \ \_____  \/    ~    \
+//  |     \   |    |___/    |    \/        \    Y    /
+//  \___  /   |_______ \____|__  /_______  /\___|_  /
+//      \/            \/       \/        \/       \/
+
+type Flash struct {
+	ctx *macaron.Context
+	url.Values
+	ErrorMsg, WarningMsg, InfoMsg, SuccessMsg string
+}
+
+func (f *Flash) set(name, msg string, current ...bool) {
+	isShow := false
+	if (len(current) == 0 && macaron.FlashNow) ||
+		(len(current) > 0 && current[0]) {
+		isShow = true
+	}
+
+	if isShow {
+		f.ctx.Data["Flash"] = f
+	} else {
+		f.Set(name, msg)
+	}
+}
+
+func (f *Flash) Error(msg string, current ...bool) {
+	f.ErrorMsg = msg
+	f.set("error", msg, current...)
+}
+
+func (f *Flash) Warning(msg string, current ...bool) {
+	f.WarningMsg = msg
+	f.set("warning", msg, current...)
+}
+
+func (f *Flash) Info(msg string, current ...bool) {
+	f.InfoMsg = msg
+	f.set("info", msg, current...)
+}
+
+func (f *Flash) Success(msg string, current ...bool) {
+	f.SuccessMsg = msg
+	f.set("success", msg, current...)
+}

+ 60 - 0
vendor/github.com/go-macaron/session/utils.go

@@ -0,0 +1,60 @@
+// Copyright 2013 Beego Authors
+// Copyright 2014 The Macaron Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package session
+
+import (
+	"bytes"
+	"crypto/rand"
+	"encoding/gob"
+	"io"
+
+	"github.com/Unknwon/com"
+)
+
+func init() {
+	gob.Register([]interface{}{})
+	gob.Register(map[int]interface{}{})
+	gob.Register(map[string]interface{}{})
+	gob.Register(map[interface{}]interface{}{})
+	gob.Register(map[string]string{})
+	gob.Register(map[int]string{})
+	gob.Register(map[int]int{})
+	gob.Register(map[int]int64{})
+}
+
+func EncodeGob(obj map[interface{}]interface{}) ([]byte, error) {
+	for _, v := range obj {
+		gob.Register(v)
+	}
+	buf := bytes.NewBuffer(nil)
+	err := gob.NewEncoder(buf).Encode(obj)
+	return buf.Bytes(), err
+}
+
+func DecodeGob(encoded []byte) (out map[interface{}]interface{}, err error) {
+	buf := bytes.NewBuffer(encoded)
+	err = gob.NewDecoder(buf).Decode(&out)
+	return out, err
+}
+
+// generateRandomKey creates a random key with the given strength.
+func generateRandomKey(strength int) []byte {
+	k := make([]byte, strength)
+	if n, err := io.ReadFull(rand.Reader, k); n != strength || err != nil {
+		return com.RandomCreateBytes(strength)
+	}
+	return k
+}

+ 191 - 0
vendor/github.com/go-macaron/toolbox/LICENSE

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

+ 110 - 0
vendor/github.com/go-macaron/toolbox/README.md

@@ -0,0 +1,110 @@
+toolbox
+=======
+
+Middleware toolbox provides health chcek, pprof, profile and statistic services for [Macaron](https://github.com/go-macaron/macaron).
+
+[API Reference](https://gowalker.org/github.com/go-macaron/toolbox)
+
+### Installation
+
+	go get github.com/go-macaron/toolbox
+	
+## Usage
+
+```go
+// main.go
+import (
+	"gopkg.in/macaron.v1"
+	"github.com/go-macaron/toolbox"
+)
+
+func main() {
+  	m := macaron.Classic()
+  	m.Use(toolbox.Toolboxer(m))
+	m.Run()
+}
+```
+
+Open your browser and visit `http://localhost:4000/debug` to see the effects.
+
+## Options
+
+`toolbox.Toolboxer` comes with a variety of configuration options:
+
+```go
+type dummyChecker struct {
+}
+
+func (dc *dummyChecker) Desc() string {
+	return "Dummy checker"
+}
+
+func (dc *dummyChecker) Check() error {
+	return nil
+}
+
+// ...
+m.Use(toolbox.Toolboxer(m, toolbox.Options{
+	URLPrefix:			"/debug",			// URL prefix for toolbox dashboard.
+	HealthCheckURL:		"/healthcheck", 	// URL for health check request.
+	HealthCheckers: []HealthChecker{
+		new(dummyChecker),
+	},										// Health checkers.
+	HealthCheckFuncs: []*toolbox.HealthCheckFuncDesc{
+		&toolbox.HealthCheckFuncDesc{
+			Desc: "Database connection",
+			Func: func() error { return "OK" },
+		},
+	},										// Health check functions.
+	PprofURLPrefix:		"/debug/pprof/", 	// URL prefix of pprof.
+	ProfileURLPrefix:	"/debug/profile/", 	// URL prefix of profile.
+	ProfilePath:		"profile", 			// Path store profile files.
+}))
+// ...
+```
+
+## Route Statistic
+
+Toolbox also comes with a route call statistic functionality:
+
+```go
+import (
+	"os"
+	"time"
+	//...
+	"github.com/go-macaron/toolbox"
+)
+
+func main() {
+	//...
+	m.Get("/", func(t toolbox.Toolbox) {
+		start := time.Now()
+		
+		// Other operations.
+		
+		t.AddStatistics("GET", "/", time.Since(start))
+	})
+	
+	m.Get("/dump", func(t toolbox.Toolbox) {
+		t.GetMap(os.Stdout)
+	})
+}
+```
+
+Output take from test:
+
+```
++---------------------------------------------------+------------+------------------+------------------+------------------+------------------+------------------+
+| Request URL                                       | Method     | Times            | Total Used(s)    | Max Used(μs)     | Min Used(μs)     | Avg Used(μs)     |
++---------------------------------------------------+------------+------------------+------------------+------------------+------------------+------------------+
+| /api/user                                         | POST       |                2 |         0.000122 |       120.000000 |         2.000000 |        61.000000 |
+| /api/user                                         | GET        |                1 |         0.000013 |        13.000000 |        13.000000 |        13.000000 |
+| /api/user                                         | DELETE     |                1 |         0.000001 |         1.400000 |         1.400000 |         1.400000 |
+| /api/admin                                        | POST       |                1 |         0.000014 |        14.000000 |        14.000000 |        14.000000 |
+| /api/user/unknwon                                 | POST       |                1 |         0.000012 |        12.000000 |        12.000000 |        12.000000 |
++---------------------------------------------------+------------+------------------+------------------+------------------+------------------+------------------+
+```
+
+## License
+
+This project is under Apache v2 License. See the [LICENSE](LICENSE) file for the full license text.

+ 83 - 0
vendor/github.com/go-macaron/toolbox/healthcheck.go

@@ -0,0 +1,83 @@
+// Copyright 2013 Beego Authors
+// Copyright 2014 The Macaron Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package toolbox
+
+import (
+	"bytes"
+)
+
+// HealthChecker represents a health check instance.
+type HealthChecker interface {
+	Desc() string
+	Check() error
+}
+
+// HealthCheckFunc represents a callable function for health check.
+type HealthCheckFunc func() error
+
+// HealthCheckFunc represents a callable function for health check with description.
+type HealthCheckFuncDesc struct {
+	Desc string
+	Func HealthCheckFunc
+}
+
+type healthCheck struct {
+	desc string
+	HealthChecker
+	check HealthCheckFunc // Not nil if add job as a function.
+}
+
+// AddHealthCheck adds new health check job.
+func (t *toolbox) AddHealthCheck(hc HealthChecker) {
+	t.healthCheckJobs = append(t.healthCheckJobs, &healthCheck{
+		HealthChecker: hc,
+	})
+}
+
+// AddHealthCheckFunc adds a function as a new health check job.
+func (t *toolbox) AddHealthCheckFunc(desc string, fn HealthCheckFunc) {
+	t.healthCheckJobs = append(t.healthCheckJobs, &healthCheck{
+		desc:  desc,
+		check: fn,
+	})
+}
+
+func (t *toolbox) handleHealthCheck() string {
+	if len(t.healthCheckJobs) == 0 {
+		return "no health check jobs"
+	}
+
+	var buf bytes.Buffer
+	var err error
+	for _, job := range t.healthCheckJobs {
+		buf.WriteString("* ")
+		if job.check != nil {
+			buf.WriteString(job.desc)
+			err = job.check()
+		} else {
+			buf.WriteString(job.Desc())
+			err = job.Check()
+		}
+		buf.WriteString(": ")
+		if err == nil {
+			buf.WriteString("OK")
+		} else {
+			buf.WriteString(err.Error())
+		}
+		buf.WriteString("\n")
+	}
+	return buf.String()
+}

+ 163 - 0
vendor/github.com/go-macaron/toolbox/profile.go

@@ -0,0 +1,163 @@
+// Copyright 2013 Beego Authors
+// Copyright 2014 The Macaron Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package toolbox
+
+import (
+	"bytes"
+	"errors"
+	"fmt"
+	"io"
+	"os"
+	"path"
+	"runtime"
+	"runtime/debug"
+	"runtime/pprof"
+	"time"
+
+	"github.com/Unknwon/com"
+	"gopkg.in/macaron.v1"
+)
+
+var (
+	profilePath  string
+	pid          int
+	startTime    = time.Now()
+	inCPUProfile bool
+)
+
+// StartCPUProfile starts CPU profile monitor.
+func StartCPUProfile() error {
+	if inCPUProfile {
+		return errors.New("CPU profile has alreday been started!")
+	}
+	inCPUProfile = true
+
+	os.MkdirAll(profilePath, os.ModePerm)
+	f, err := os.Create(path.Join(profilePath, "cpu-"+com.ToStr(pid)+".pprof"))
+	if err != nil {
+		panic("fail to record CPU profile: " + err.Error())
+	}
+	pprof.StartCPUProfile(f)
+	return nil
+}
+
+// StopCPUProfile stops CPU profile monitor.
+func StopCPUProfile() error {
+	if !inCPUProfile {
+		return errors.New("CPU profile hasn't been started!")
+	}
+	pprof.StopCPUProfile()
+	inCPUProfile = false
+	return nil
+}
+
+func init() {
+	pid = os.Getpid()
+}
+
+// DumpMemProf dumps memory profile in pprof.
+func DumpMemProf(w io.Writer) {
+	pprof.WriteHeapProfile(w)
+}
+
+func dumpMemProf() {
+	os.MkdirAll(profilePath, os.ModePerm)
+	f, err := os.Create(path.Join(profilePath, "mem-"+com.ToStr(pid)+".memprof"))
+	if err != nil {
+		panic("fail to record memory profile: " + err.Error())
+	}
+	runtime.GC()
+	DumpMemProf(f)
+	f.Close()
+}
+
+func avg(items []time.Duration) time.Duration {
+	var sum time.Duration
+	for _, item := range items {
+		sum += item
+	}
+	return time.Duration(int64(sum) / int64(len(items)))
+}
+
+func dumpGC(memStats *runtime.MemStats, gcstats *debug.GCStats, w io.Writer) {
+
+	if gcstats.NumGC > 0 {
+		lastPause := gcstats.Pause[0]
+		elapsed := time.Now().Sub(startTime)
+		overhead := float64(gcstats.PauseTotal) / float64(elapsed) * 100
+		allocatedRate := float64(memStats.TotalAlloc) / elapsed.Seconds()
+
+		fmt.Fprintf(w, "NumGC:%d Pause:%s Pause(Avg):%s Overhead:%3.2f%% Alloc:%s Sys:%s Alloc(Rate):%s/s Histogram:%s %s %s \n",
+			gcstats.NumGC,
+			com.ToStr(lastPause),
+			com.ToStr(avg(gcstats.Pause)),
+			overhead,
+			com.HumaneFileSize(memStats.Alloc),
+			com.HumaneFileSize(memStats.Sys),
+			com.HumaneFileSize(uint64(allocatedRate)),
+			com.ToStr(gcstats.PauseQuantiles[94]),
+			com.ToStr(gcstats.PauseQuantiles[98]),
+			com.ToStr(gcstats.PauseQuantiles[99]))
+	} else {
+		// while GC has disabled
+		elapsed := time.Now().Sub(startTime)
+		allocatedRate := float64(memStats.TotalAlloc) / elapsed.Seconds()
+
+		fmt.Fprintf(w, "Alloc:%s Sys:%s Alloc(Rate):%s/s\n",
+			com.HumaneFileSize(memStats.Alloc),
+			com.HumaneFileSize(memStats.Sys),
+			com.HumaneFileSize(uint64(allocatedRate)))
+	}
+}
+
+// DumpGCSummary dumps GC information to io.Writer
+func DumpGCSummary(w io.Writer) {
+	memStats := &runtime.MemStats{}
+	runtime.ReadMemStats(memStats)
+	gcstats := &debug.GCStats{PauseQuantiles: make([]time.Duration, 100)}
+	debug.ReadGCStats(gcstats)
+
+	dumpGC(memStats, gcstats, w)
+}
+
+func handleProfile(ctx *macaron.Context) string {
+	switch ctx.Query("op") {
+	case "startcpu":
+		if err := StartCPUProfile(); err != nil {
+			return err.Error()
+		}
+	case "stopcpu":
+		if err := StopCPUProfile(); err != nil {
+			return err.Error()
+		}
+	case "mem":
+		dumpMemProf()
+	case "gc":
+		var buf bytes.Buffer
+		DumpGCSummary(&buf)
+		return string(buf.Bytes())
+	default:
+		return fmt.Sprintf(`<p>Available operations:</p>
+<ol>
+	<li><a href="%[1]s?op=startcpu">Start CPU profile</a></li>
+	<li><a href="%[1]s?op=stopcpu">Stop CPU profile</a></li>
+	<li><a href="%[1]s?op=mem">Dump memory profile</a></li>
+	<li><a href="%[1]s?op=gc">Dump GC summary</a></li>
+</ol>`, opt.ProfileURLPrefix)
+	}
+	ctx.Redirect(opt.ProfileURLPrefix)
+	return ""
+}

+ 138 - 0
vendor/github.com/go-macaron/toolbox/statistic.go

@@ -0,0 +1,138 @@
+// Copyright 2013 Beego Authors
+// Copyright 2014 The Macaron Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package toolbox
+
+import (
+	"encoding/json"
+	"fmt"
+	"io"
+	"strings"
+	"sync"
+	"time"
+)
+
+// Statistics struct
+type Statistics struct {
+	RequestUrl string
+	RequestNum int64
+	MinTime    time.Duration
+	MaxTime    time.Duration
+	TotalTime  time.Duration
+}
+
+// UrlMap contains several statistics struct to log different data
+type UrlMap struct {
+	lock        sync.RWMutex
+	LengthLimit int // limit the urlmap's length if it's equal to 0 there's no limit
+	urlmap      map[string]map[string]*Statistics
+}
+
+// add statistics task.
+// it needs request method, request url and statistics time duration
+func (m *UrlMap) AddStatistics(requestMethod, requestUrl string, requesttime time.Duration) {
+	m.lock.Lock()
+	defer m.lock.Unlock()
+
+	if method, ok := m.urlmap[requestUrl]; ok {
+		if s, ok := method[requestMethod]; ok {
+			s.RequestNum += 1
+			if s.MaxTime < requesttime {
+				s.MaxTime = requesttime
+			}
+			if s.MinTime > requesttime {
+				s.MinTime = requesttime
+			}
+			s.TotalTime += requesttime
+		} else {
+			nb := &Statistics{
+				RequestUrl: requestUrl,
+				RequestNum: 1,
+				MinTime:    requesttime,
+				MaxTime:    requesttime,
+				TotalTime:  requesttime,
+			}
+			m.urlmap[requestUrl][requestMethod] = nb
+		}
+
+	} else {
+		if m.LengthLimit > 0 && m.LengthLimit <= len(m.urlmap) {
+			return
+		}
+		methodmap := make(map[string]*Statistics)
+		nb := &Statistics{
+			RequestUrl: requestUrl,
+			RequestNum: 1,
+			MinTime:    requesttime,
+			MaxTime:    requesttime,
+			TotalTime:  requesttime,
+		}
+		methodmap[requestMethod] = nb
+		m.urlmap[requestUrl] = methodmap
+	}
+}
+
+// put url statistics result in io.Writer
+func (m *UrlMap) GetMap(w io.Writer) {
+	m.lock.RLock()
+	defer m.lock.RUnlock()
+
+	sep := fmt.Sprintf("+%s+%s+%s+%s+%s+%s+%s+\n", strings.Repeat("-", 51), strings.Repeat("-", 12),
+		strings.Repeat("-", 18), strings.Repeat("-", 18), strings.Repeat("-", 18), strings.Repeat("-", 18), strings.Repeat("-", 18))
+	fmt.Fprintf(w, sep)
+	fmt.Fprintf(w, "| % -50s| % -10s | % -16s | % -16s | % -16s | % -16s | % -16s |\n", "Request URL", "Method", "Times", "Total Used(s)", "Max Used(μs)", "Min Used(μs)", "Avg Used(μs)")
+	fmt.Fprintf(w, sep)
+
+	for k, v := range m.urlmap {
+		for kk, vv := range v {
+			fmt.Fprintf(w, "| % -50s| % -10s | % 16d | % 16f | % 16.6f | % 16.6f | % 16.6f |\n", k,
+				kk, vv.RequestNum, vv.TotalTime.Seconds(), float64(vv.MaxTime.Nanoseconds())/1000,
+				float64(vv.MinTime.Nanoseconds())/1000, float64(time.Duration(int64(vv.TotalTime)/vv.RequestNum).Nanoseconds())/1000,
+			)
+		}
+	}
+	fmt.Fprintf(w, sep)
+}
+
+type URLMapInfo struct {
+	URL       string  `json:"url"`
+	Method    string  `json:"method"`
+	Times     int64   `json:"times"`
+	TotalUsed float64 `json:"total_used"`
+	MaxUsed   float64 `json:"max_used"`
+	MinUsed   float64 `json:"min_used"`
+	AvgUsed   float64 `json:"avg_used"`
+}
+
+func (m *UrlMap) JSON(w io.Writer) {
+	infos := make([]*URLMapInfo, 0, len(m.urlmap))
+	for k, v := range m.urlmap {
+		for kk, vv := range v {
+			infos = append(infos, &URLMapInfo{
+				URL:       k,
+				Method:    kk,
+				Times:     vv.RequestNum,
+				TotalUsed: vv.TotalTime.Seconds(),
+				MaxUsed:   float64(vv.MaxTime.Nanoseconds()) / 1000,
+				MinUsed:   float64(vv.MinTime.Nanoseconds()) / 1000,
+				AvgUsed:   float64(time.Duration(int64(vv.TotalTime)/vv.RequestNum).Nanoseconds()) / 1000,
+			})
+		}
+	}
+
+	if err := json.NewEncoder(w).Encode(infos); err != nil {
+		panic("URLMap.JSON: " + err.Error())
+	}
+}

+ 154 - 0
vendor/github.com/go-macaron/toolbox/toolbox.go

@@ -0,0 +1,154 @@
+// Copyright 2014 The Macaron Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+// Package toolbox is a middleware that provides health check, pprof, profile and statistic services for Macaron.
+package toolbox
+
+import (
+	"fmt"
+	"io"
+	"net/http"
+	"net/http/pprof"
+	"path"
+	"time"
+
+	"gopkg.in/macaron.v1"
+)
+
+const _VERSION = "0.1.2"
+
+func Version() string {
+	return _VERSION
+}
+
+// Toolbox represents a tool box service for Macaron instance.
+type Toolbox interface {
+	AddHealthCheck(HealthChecker)
+	AddHealthCheckFunc(string, HealthCheckFunc)
+	AddStatistics(string, string, time.Duration)
+	GetMap(io.Writer)
+	JSON(io.Writer)
+}
+
+type toolbox struct {
+	*UrlMap
+	healthCheckJobs []*healthCheck
+}
+
+// Options represents a struct for specifying configuration options for the Toolbox middleware.
+type Options struct {
+	// URL prefix for toolbox dashboard. Default is "/debug".
+	URLPrefix string
+	// URL for health check request. Default is "/healthcheck".
+	HealthCheckURL string
+	// Health checkers.
+	HealthCheckers []HealthChecker
+	// Health check functions.
+	HealthCheckFuncs []*HealthCheckFuncDesc
+	// URL for URL map json. Default is "/urlmap.json".
+	URLMapPrefix string
+	// URL prefix of pprof. Default is "/debug/pprof/".
+	PprofURLPrefix string
+	// URL prefix of profile. Default is "/debug/profile/".
+	ProfileURLPrefix string
+	// Path store profile files. Default is "profile".
+	ProfilePath string
+}
+
+var opt Options
+
+func prepareOptions(options []Options) {
+	if len(options) > 0 {
+		opt = options[0]
+	}
+
+	// Defaults.
+	if len(opt.URLPrefix) == 0 {
+		opt.URLPrefix = "/debug"
+	}
+	if len(opt.HealthCheckURL) == 0 {
+		opt.HealthCheckURL = "/healthcheck"
+	}
+	if len(opt.URLMapPrefix) == 0 {
+		opt.URLMapPrefix = "/urlmap.json"
+	}
+	if len(opt.PprofURLPrefix) == 0 {
+		opt.PprofURLPrefix = "/debug/pprof/"
+	} else if opt.PprofURLPrefix[len(opt.PprofURLPrefix)-1] != '/' {
+		opt.PprofURLPrefix += "/"
+	}
+	if len(opt.ProfileURLPrefix) == 0 {
+		opt.ProfileURLPrefix = "/debug/profile/"
+	} else if opt.ProfileURLPrefix[len(opt.ProfileURLPrefix)-1] != '/' {
+		opt.ProfileURLPrefix += "/"
+	}
+	if len(opt.ProfilePath) == 0 {
+		opt.ProfilePath = path.Join(macaron.Root, "profile")
+	}
+}
+
+func dashboard(ctx *macaron.Context) string {
+	return fmt.Sprintf(`<p>Toolbox Index:</p>
+	<ol>
+	    <li><a href="%s">Pprof Information</a></li>
+        <li><a href="%s">Profile Operations</a></li>
+	</ol>`, opt.PprofURLPrefix, opt.ProfileURLPrefix)
+}
+
+var _ Toolbox = &toolbox{}
+
+// Toolboxer is a middleware provides health check, pprof, profile and statistic services for your application.
+func Toolboxer(m *macaron.Macaron, options ...Options) macaron.Handler {
+	prepareOptions(options)
+	t := &toolbox{
+		healthCheckJobs: make([]*healthCheck, 0, len(opt.HealthCheckers)+len(opt.HealthCheckFuncs)),
+	}
+
+	// Dashboard.
+	m.Get(opt.URLPrefix, dashboard)
+
+	// Health check.
+	for _, hc := range opt.HealthCheckers {
+		t.AddHealthCheck(hc)
+	}
+	for _, fd := range opt.HealthCheckFuncs {
+		t.AddHealthCheckFunc(fd.Desc, fd.Func)
+	}
+	m.Get(opt.HealthCheckURL, t.handleHealthCheck)
+
+	// URL map.
+	m.Get(opt.URLMapPrefix, func(rw http.ResponseWriter) {
+		t.JSON(rw)
+	})
+
+	// Pprof.
+	m.Any(path.Join(opt.PprofURLPrefix, "cmdline"), pprof.Cmdline)
+	m.Any(path.Join(opt.PprofURLPrefix, "profile"), pprof.Profile)
+	m.Any(path.Join(opt.PprofURLPrefix, "symbol"), pprof.Symbol)
+	m.Any(opt.PprofURLPrefix, pprof.Index)
+	m.Any(path.Join(opt.PprofURLPrefix, "*"), pprof.Index)
+
+	// Profile.
+	profilePath = opt.ProfilePath
+	m.Get(opt.ProfileURLPrefix, handleProfile)
+
+	// Routes statistic.
+	t.UrlMap = &UrlMap{
+		urlmap: make(map[string]map[string]*Statistics),
+	}
+
+	return func(ctx *macaron.Context) {
+		ctx.MapTo(t, (*Toolbox)(nil))
+	}
+}

+ 52 - 0
vendor/github.com/go-sql-driver/mysql/AUTHORS

@@ -0,0 +1,52 @@
+# This is the official list of Go-MySQL-Driver authors for copyright purposes.
+
+# If you are submitting a patch, please add your name or the name of the
+# organization which holds the copyright to this list in alphabetical order.
+
+# Names should be added to this file as
+#	Name <email address>
+# The email address is not required for organizations.
+# Please keep the list sorted.
+
+
+# Individual Persons
+
+Aaron Hopkins <go-sql-driver at die.net>
+Arne Hormann <arnehormann at gmail.com>
+Carlos Nieto <jose.carlos at menteslibres.net>
+Chris Moos <chris at tech9computers.com>
+Daniel Nichter <nil at codenode.com>
+Daniël van Eeden <git at myname.nl>
+DisposaBoy <disposaboy at dby.me>
+Frederick Mayle <frederickmayle at gmail.com>
+Gustavo Kristic <gkristic at gmail.com>
+Hanno Braun <mail at hannobraun.com>
+Henri Yandell <flamefew at gmail.com>
+Hirotaka Yamamoto <ymmt2005 at gmail.com>
+INADA Naoki <songofacandy at gmail.com>
+James Harr <james.harr at gmail.com>
+Jian Zhen <zhenjl at gmail.com>
+Joshua Prunier <joshua.prunier at gmail.com>
+Julien Lefevre <julien.lefevr at gmail.com>
+Julien Schmidt <go-sql-driver at julienschmidt.com>
+Kamil Dziedzic <kamil at klecza.pl>
+Kevin Malachowski <kevin at chowski.com>
+Leonardo YongUk Kim <dalinaum at gmail.com>
+Luca Looz <luca.looz92 at gmail.com>
+Lucas Liu <extrafliu at gmail.com>
+Luke Scott <luke at webconnex.com>
+Michael Woolnough <michael.woolnough at gmail.com>
+Nicola Peduzzi <thenikso at gmail.com>
+Paul Bonser <misterpib at gmail.com>
+Runrioter Wung <runrioter at gmail.com>
+Soroush Pour <me at soroushjp.com>
+Stan Putrya <root.vagner at gmail.com>
+Stanley Gunawan <gunawan.stanley at gmail.com>
+Xiaobing Jiang <s7v7nislands at gmail.com>
+Xiuming Chen <cc at cxm.cc>
+
+# Organizations
+
+Barracuda Networks, Inc.
+Google Inc.
+Stripe Inc.

+ 103 - 0
vendor/github.com/go-sql-driver/mysql/CHANGELOG.md

@@ -0,0 +1,103 @@
+## HEAD
+
+Changes:
+
+ - Go 1.1 is no longer supported
+ - Use decimals field from MySQL to format time types (#249)
+ - Buffer optimizations (#269)
+ - TLS ServerName defaults to the host (#283)
+
+Bugfixes:
+
+ - Enable microsecond resolution on TIME, DATETIME and TIMESTAMP (#249)
+ - Fixed handling of queries without columns and rows (#255)
+ - Fixed a panic when SetKeepAlive() failed (#298)
+ - Support receiving ERR packet while reading rows (#321)
+ - Fixed reading NULL length-encoded integers in MySQL 5.6+ (#349)
+ - Fixed absolute paths support in LOAD LOCAL DATA INFILE (#356)
+ - Actually zero out bytes in handshake response (#378)
+ - Fixed race condition in registering LOAD DATA INFILE handler (#383)
+ - Fixed tests with MySQL 5.7.9+ (#380)
+ - QueryUnescape TLS config names (#397)
+ - Fixed "broken pipe" error by writing to closed socket (#390)
+
+New Features:
+ - Support for returning table alias on Columns() (#289, #359, #382)
+ - Placeholder interpolation, can be actived with the DSN parameter `interpolateParams=true` (#309, #318)
+ - Support for uint64 parameters with high bit set (#332, #345)
+ - Cleartext authentication plugin support (#327)
+
+
+
+## Version 1.2 (2014-06-03)
+
+Changes:
+
+ - We switched back to a "rolling release". `go get` installs the current master branch again
+ - Version v1 of the driver will not be maintained anymore. Go 1.0 is no longer supported by this driver
+ - Exported errors to allow easy checking from application code
+ - Enabled TCP Keepalives on TCP connections
+ - Optimized INFILE handling (better buffer size calculation, lazy init, ...)
+ - The DSN parser also checks for a missing separating slash
+ - Faster binary date / datetime to string formatting
+ - Also exported the MySQLWarning type
+ - mysqlConn.Close returns the first error encountered instead of ignoring all errors
+ - writePacket() automatically writes the packet size to the header
+ - readPacket() uses an iterative approach instead of the recursive approach to merge splitted packets
+
+New Features:
+
+ - `RegisterDial` allows the usage of a custom dial function to establish the network connection
+ - Setting the connection collation is possible with the `collation` DSN parameter. This parameter should be preferred over the `charset` parameter
+ - Logging of critical errors is configurable with `SetLogger`
+ - Google CloudSQL support
+
+Bugfixes:
+
+ - Allow more than 32 parameters in prepared statements
+ - Various old_password fixes
+ - Fixed TestConcurrent test to pass Go's race detection
+ - Fixed appendLengthEncodedInteger for large numbers
+ - Renamed readLengthEnodedString to readLengthEncodedString and skipLengthEnodedString to skipLengthEncodedString (fixed typo)
+
+
+## Version 1.1 (2013-11-02)
+
+Changes:
+
+  - Go-MySQL-Driver now requires Go 1.1
+  - Connections now use the collation `utf8_general_ci` by default. Adding `&charset=UTF8` to the DSN should not be necessary anymore
+  - Made closing rows and connections error tolerant. This allows for example deferring rows.Close() without checking for errors
+  - `[]byte(nil)` is now treated as a NULL value. Before, it was treated like an empty string / `[]byte("")`
+  - DSN parameter values must now be url.QueryEscape'ed. This allows text values to contain special characters, such as '&'.
+  - Use the IO buffer also for writing. This results in zero allocations (by the driver) for most queries
+  - Optimized the buffer for reading
+  - stmt.Query now caches column metadata
+  - New Logo
+  - Changed the copyright header to include all contributors
+  - Improved the LOAD INFILE documentation
+  - The driver struct is now exported to make the driver directly accessible
+  - Refactored the driver tests
+  - Added more benchmarks and moved all to a separate file
+  - Other small refactoring
+
+New Features:
+
+  - Added *old_passwords* support: Required in some cases, but must be enabled by adding `allowOldPasswords=true` to the DSN since it is insecure
+  - Added a `clientFoundRows` parameter: Return the number of matching rows instead of the number of rows changed on UPDATEs
+  - Added TLS/SSL support: Use a TLS/SSL encrypted connection to the server. Custom TLS configs can be registered and used
+
+Bugfixes:
+
+  - Fixed MySQL 4.1 support: MySQL 4.1 sends packets with lengths which differ from the specification
+  - Convert to DB timezone when inserting `time.Time`
+  - Splitted packets (more than 16MB) are now merged correctly
+  - Fixed false positive `io.EOF` errors when the data was fully read
+  - Avoid panics on reuse of closed connections
+  - Fixed empty string producing false nil values
+  - Fixed sign byte for positive TIME fields
+
+
+## Version 1.0 (2013-05-14)
+
+Initial Release

+ 23 - 0
vendor/github.com/go-sql-driver/mysql/CONTRIBUTING.md

@@ -0,0 +1,23 @@
+# Contributing Guidelines
+
+## Reporting Issues
+
+Before creating a new Issue, please check first if a similar Issue [already exists](https://github.com/go-sql-driver/mysql/issues?state=open) or was [recently closed](https://github.com/go-sql-driver/mysql/issues?direction=desc&page=1&sort=updated&state=closed).
+
+## Contributing Code
+
+By contributing to this project, you share your code under the Mozilla Public License 2, as specified in the LICENSE file.
+Don't forget to add yourself to the AUTHORS file.
+
+### Code Review
+
+Everyone is invited to review and comment on pull requests.
+If it looks fine to you, comment with "LGTM" (Looks good to me).
+
+If changes are required, notice the reviewers with "PTAL" (Please take another look) after committing the fixes.
+
+Before merging the Pull Request, at least one [team member](https://github.com/go-sql-driver?tab=members) must have commented with "LGTM".
+
+## Development Ideas
+
+If you are looking for ideas for code contributions, please check our [Development Ideas](https://github.com/go-sql-driver/mysql/wiki/Development-Ideas) Wiki page.

+ 21 - 0
vendor/github.com/go-sql-driver/mysql/ISSUE_TEMPLATE.md

@@ -0,0 +1,21 @@
+### Issue description
+Tell us what should happen and what happens instead
+
+### Example code
+```go
+If possible, please enter some example code here to reproduce the issue.
+```
+
+### Error log
+```
+If you have an error log, please paste it here.
+```
+
+### Configuration
+*Driver version (or git SHA):*
+
+*Go version:* run `go version` in your console
+
+*Server version:* E.g. MySQL 5.6, MariaDB 10.0.20
+
+*Server OS:* E.g. Debian 8.1 (Jessie), Windows 10

+ 373 - 0
vendor/github.com/go-sql-driver/mysql/LICENSE

@@ -0,0 +1,373 @@
+Mozilla Public License Version 2.0
+==================================
+
+1. Definitions
+--------------
+
+1.1. "Contributor"
+    means each individual or legal entity that creates, contributes to
+    the creation of, or owns Covered Software.
+
+1.2. "Contributor Version"
+    means the combination of the Contributions of others (if any) used
+    by a Contributor and that particular Contributor's Contribution.
+
+1.3. "Contribution"
+    means Covered Software of a particular Contributor.
+
+1.4. "Covered Software"
+    means Source Code Form to which the initial Contributor has attached
+    the notice in Exhibit A, the Executable Form of such Source Code
+    Form, and Modifications of such Source Code Form, in each case
+    including portions thereof.
+
+1.5. "Incompatible With Secondary Licenses"
+    means
+
+    (a) that the initial Contributor has attached the notice described
+        in Exhibit B to the Covered Software; or
+
+    (b) that the Covered Software was made available under the terms of
+        version 1.1 or earlier of the License, but not also under the
+        terms of a Secondary License.
+
+1.6. "Executable Form"
+    means any form of the work other than Source Code Form.
+
+1.7. "Larger Work"
+    means a work that combines Covered Software with other material, in 
+    a separate file or files, that is not Covered Software.
+
+1.8. "License"
+    means this document.
+
+1.9. "Licensable"
+    means having the right to grant, to the maximum extent possible,
+    whether at the time of the initial grant or subsequently, any and
+    all of the rights conveyed by this License.
+
+1.10. "Modifications"
+    means any of the following:
+
+    (a) any file in Source Code Form that results from an addition to,
+        deletion from, or modification of the contents of Covered
+        Software; or
+
+    (b) any new file in Source Code Form that contains any Covered
+        Software.
+
+1.11. "Patent Claims" of a Contributor
+    means any patent claim(s), including without limitation, method,
+    process, and apparatus claims, in any patent Licensable by such
+    Contributor that would be infringed, but for the grant of the
+    License, by the making, using, selling, offering for sale, having
+    made, import, or transfer of either its Contributions or its
+    Contributor Version.
+
+1.12. "Secondary License"
+    means either the GNU General Public License, Version 2.0, the GNU
+    Lesser General Public License, Version 2.1, the GNU Affero General
+    Public License, Version 3.0, or any later versions of those
+    licenses.
+
+1.13. "Source Code Form"
+    means the form of the work preferred for making modifications.
+
+1.14. "You" (or "Your")
+    means an individual or a legal entity exercising rights under this
+    License. For legal entities, "You" includes any entity that
+    controls, is controlled by, or is under common control with You. For
+    purposes of this definition, "control" means (a) the power, direct
+    or indirect, to cause the direction or management of such entity,
+    whether by contract or otherwise, or (b) ownership of more than
+    fifty percent (50%) of the outstanding shares or beneficial
+    ownership of such entity.
+
+2. License Grants and Conditions
+--------------------------------
+
+2.1. Grants
+
+Each Contributor hereby grants You a world-wide, royalty-free,
+non-exclusive license:
+
+(a) under intellectual property rights (other than patent or trademark)
+    Licensable by such Contributor to use, reproduce, make available,
+    modify, display, perform, distribute, and otherwise exploit its
+    Contributions, either on an unmodified basis, with Modifications, or
+    as part of a Larger Work; and
+
+(b) under Patent Claims of such Contributor to make, use, sell, offer
+    for sale, have made, import, and otherwise transfer either its
+    Contributions or its Contributor Version.
+
+2.2. Effective Date
+
+The licenses granted in Section 2.1 with respect to any Contribution
+become effective for each Contribution on the date the Contributor first
+distributes such Contribution.
+
+2.3. Limitations on Grant Scope
+
+The licenses granted in this Section 2 are the only rights granted under
+this License. No additional rights or licenses will be implied from the
+distribution or licensing of Covered Software under this License.
+Notwithstanding Section 2.1(b) above, no patent license is granted by a
+Contributor:
+
+(a) for any code that a Contributor has removed from Covered Software;
+    or
+
+(b) for infringements caused by: (i) Your and any other third party's
+    modifications of Covered Software, or (ii) the combination of its
+    Contributions with other software (except as part of its Contributor
+    Version); or
+
+(c) under Patent Claims infringed by Covered Software in the absence of
+    its Contributions.
+
+This License does not grant any rights in the trademarks, service marks,
+or logos of any Contributor (except as may be necessary to comply with
+the notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+No Contributor makes additional grants as a result of Your choice to
+distribute the Covered Software under a subsequent version of this
+License (see Section 10.2) or under the terms of a Secondary License (if
+permitted under the terms of Section 3.3).
+
+2.5. Representation
+
+Each Contributor represents that the Contributor believes its
+Contributions are its original creation(s) or it has sufficient rights
+to grant the rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+This License is not intended to limit any rights You have under
+applicable copyright doctrines of fair use, fair dealing, or other
+equivalents.
+
+2.7. Conditions
+
+Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
+in Section 2.1.
+
+3. Responsibilities
+-------------------
+
+3.1. Distribution of Source Form
+
+All distribution of Covered Software in Source Code Form, including any
+Modifications that You create or to which You contribute, must be under
+the terms of this License. You must inform recipients that the Source
+Code Form of the Covered Software is governed by the terms of this
+License, and how they can obtain a copy of this License. You may not
+attempt to alter or restrict the recipients' rights in the Source Code
+Form.
+
+3.2. Distribution of Executable Form
+
+If You distribute Covered Software in Executable Form then:
+
+(a) such Covered Software must also be made available in Source Code
+    Form, as described in Section 3.1, and You must inform recipients of
+    the Executable Form how they can obtain a copy of such Source Code
+    Form by reasonable means in a timely manner, at a charge no more
+    than the cost of distribution to the recipient; and
+
+(b) You may distribute such Executable Form under the terms of this
+    License, or sublicense it under different terms, provided that the
+    license for the Executable Form does not attempt to limit or alter
+    the recipients' rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+You may create and distribute a Larger Work under terms of Your choice,
+provided that You also comply with the requirements of this License for
+the Covered Software. If the Larger Work is a combination of Covered
+Software with a work governed by one or more Secondary Licenses, and the
+Covered Software is not Incompatible With Secondary Licenses, this
+License permits You to additionally distribute such Covered Software
+under the terms of such Secondary License(s), so that the recipient of
+the Larger Work may, at their option, further distribute the Covered
+Software under the terms of either this License or such Secondary
+License(s).
+
+3.4. Notices
+
+You may not remove or alter the substance of any license notices
+(including copyright notices, patent notices, disclaimers of warranty,
+or limitations of liability) contained within the Source Code Form of
+the Covered Software, except that You may alter any license notices to
+the extent required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+You may choose to offer, and to charge a fee for, warranty, support,
+indemnity or liability obligations to one or more recipients of Covered
+Software. However, You may do so only on Your own behalf, and not on
+behalf of any Contributor. You must make it absolutely clear that any
+such warranty, support, indemnity, or liability obligation is offered by
+You alone, and You hereby agree to indemnify every Contributor for any
+liability incurred by such Contributor as a result of warranty, support,
+indemnity or liability terms You offer. You may include additional
+disclaimers of warranty and limitations of liability specific to any
+jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+---------------------------------------------------
+
+If it is impossible for You to comply with any of the terms of this
+License with respect to some or all of the Covered Software due to
+statute, judicial order, or regulation then You must: (a) comply with
+the terms of this License to the maximum extent possible; and (b)
+describe the limitations and the code they affect. Such description must
+be placed in a text file included with all distributions of the Covered
+Software under this License. Except to the extent prohibited by statute
+or regulation, such description must be sufficiently detailed for a
+recipient of ordinary skill to be able to understand it.
+
+5. Termination
+--------------
+
+5.1. The rights granted under this License will terminate automatically
+if You fail to comply with any of its terms. However, if You become
+compliant, then the rights granted under this License from a particular
+Contributor are reinstated (a) provisionally, unless and until such
+Contributor explicitly and finally terminates Your grants, and (b) on an
+ongoing basis, if such Contributor fails to notify You of the
+non-compliance by some reasonable means prior to 60 days after You have
+come back into compliance. Moreover, Your grants from a particular
+Contributor are reinstated on an ongoing basis if such Contributor
+notifies You of the non-compliance by some reasonable means, this is the
+first time You have received notice of non-compliance with this License
+from such Contributor, and You become compliant prior to 30 days after
+Your receipt of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+infringement claim (excluding declaratory judgment actions,
+counter-claims, and cross-claims) alleging that a Contributor Version
+directly or indirectly infringes any patent, then the rights granted to
+You by any and all Contributors for the Covered Software under Section
+2.1 of this License shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all
+end user license agreements (excluding distributors and resellers) which
+have been validly granted by You or Your distributors under this License
+prior to termination shall survive termination.
+
+************************************************************************
+*                                                                      *
+*  6. Disclaimer of Warranty                                           *
+*  -------------------------                                           *
+*                                                                      *
+*  Covered Software is provided under this License on an "as is"       *
+*  basis, without warranty of any kind, either expressed, implied, or  *
+*  statutory, including, without limitation, warranties that the       *
+*  Covered Software is free of defects, merchantable, fit for a        *
+*  particular purpose or non-infringing. The entire risk as to the     *
+*  quality and performance of the Covered Software is with You.        *
+*  Should any Covered Software prove defective in any respect, You     *
+*  (not any Contributor) assume the cost of any necessary servicing,   *
+*  repair, or correction. This disclaimer of warranty constitutes an   *
+*  essential part of this License. No use of any Covered Software is   *
+*  authorized under this License except under this disclaimer.         *
+*                                                                      *
+************************************************************************
+
+************************************************************************
+*                                                                      *
+*  7. Limitation of Liability                                          *
+*  --------------------------                                          *
+*                                                                      *
+*  Under no circumstances and under no legal theory, whether tort      *
+*  (including negligence), contract, or otherwise, shall any           *
+*  Contributor, or anyone who distributes Covered Software as          *
+*  permitted above, be liable to You for any direct, indirect,         *
+*  special, incidental, or consequential damages of any character      *
+*  including, without limitation, damages for lost profits, loss of    *
+*  goodwill, work stoppage, computer failure or malfunction, or any    *
+*  and all other commercial damages or losses, even if such party      *
+*  shall have been informed of the possibility of such damages. This   *
+*  limitation of liability shall not apply to liability for death or   *
+*  personal injury resulting from such party's negligence to the       *
+*  extent applicable law prohibits such limitation. Some               *
+*  jurisdictions do not allow the exclusion or limitation of           *
+*  incidental or consequential damages, so this exclusion and          *
+*  limitation may not apply to You.                                    *
+*                                                                      *
+************************************************************************
+
+8. Litigation
+-------------
+
+Any litigation relating to this License may be brought only in the
+courts of a jurisdiction where the defendant maintains its principal
+place of business and such litigation shall be governed by laws of that
+jurisdiction, without reference to its conflict-of-law provisions.
+Nothing in this Section shall prevent a party's ability to bring
+cross-claims or counter-claims.
+
+9. Miscellaneous
+----------------
+
+This License represents the complete agreement concerning the subject
+matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent
+necessary to make it enforceable. Any law or regulation which provides
+that the language of a contract shall be construed against the drafter
+shall not be used to construe this License against a Contributor.
+
+10. Versions of the License
+---------------------------
+
+10.1. New Versions
+
+Mozilla Foundation is the license steward. Except as provided in Section
+10.3, no one other than the license steward has the right to modify or
+publish new versions of this License. Each version will be given a
+distinguishing version number.
+
+10.2. Effect of New Versions
+
+You may distribute the Covered Software under the terms of the version
+of the License under which You originally received the Covered Software,
+or under the terms of any subsequent version published by the license
+steward.
+
+10.3. Modified Versions
+
+If you create software not governed by this License, and you want to
+create a new license for such software, you may create and use a
+modified version of this License if you rename the license and remove
+any references to the name of the license steward (except to note that
+such modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary
+Licenses
+
+If You choose to distribute Source Code Form that is Incompatible With
+Secondary Licenses under the terms of this version of the License, the
+notice described in Exhibit B of this License must be attached.
+
+Exhibit A - Source Code Form License Notice
+-------------------------------------------
+
+  This Source Code Form is subject to the terms of the Mozilla Public
+  License, v. 2.0. If a copy of the MPL was not distributed with this
+  file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular
+file, then You may include the notice in a location (such as a LICENSE
+file in a relevant directory) where a recipient would be likely to look
+for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - "Incompatible With Secondary Licenses" Notice
+---------------------------------------------------------
+
+  This Source Code Form is "Incompatible With Secondary Licenses", as
+  defined by the Mozilla Public License, v. 2.0.

+ 9 - 0
vendor/github.com/go-sql-driver/mysql/PULL_REQUEST_TEMPLATE.md

@@ -0,0 +1,9 @@
+### Description
+Please explain the changes you made here.
+
+### Checklist
+- [ ] Code compiles correctly
+- [ ] Created tests which fail without the change (if possible)
+- [ ] All tests passing
+- [ ] Extended the README / documentation, if necessary
+- [ ] Added myself / the copyright holder to the AUTHORS file

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 420 - 0
vendor/github.com/go-sql-driver/mysql/README.md


+ 19 - 0
vendor/github.com/go-sql-driver/mysql/appengine.go

@@ -0,0 +1,19 @@
+// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
+//
+// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at http://mozilla.org/MPL/2.0/.
+
+// +build appengine
+
+package mysql
+
+import (
+	"appengine/cloudsql"
+)
+
+func init() {
+	RegisterDial("cloudsql", cloudsql.Dial)
+}

+ 147 - 0
vendor/github.com/go-sql-driver/mysql/buffer.go

@@ -0,0 +1,147 @@
+// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
+//
+// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package mysql
+
+import (
+	"io"
+	"net"
+	"time"
+)
+
+const defaultBufSize = 4096
+
+// A buffer which is used for both reading and writing.
+// This is possible since communication on each connection is synchronous.
+// In other words, we can't write and read simultaneously on the same connection.
+// The buffer is similar to bufio.Reader / Writer but zero-copy-ish
+// Also highly optimized for this particular use case.
+type buffer struct {
+	buf     []byte
+	nc      net.Conn
+	idx     int
+	length  int
+	timeout time.Duration
+}
+
+func newBuffer(nc net.Conn) buffer {
+	var b [defaultBufSize]byte
+	return buffer{
+		buf: b[:],
+		nc:  nc,
+	}
+}
+
+// fill reads into the buffer until at least _need_ bytes are in it
+func (b *buffer) fill(need int) error {
+	n := b.length
+
+	// move existing data to the beginning
+	if n > 0 && b.idx > 0 {
+		copy(b.buf[0:n], b.buf[b.idx:])
+	}
+
+	// grow buffer if necessary
+	// TODO: let the buffer shrink again at some point
+	//       Maybe keep the org buf slice and swap back?
+	if need > len(b.buf) {
+		// Round up to the next multiple of the default size
+		newBuf := make([]byte, ((need/defaultBufSize)+1)*defaultBufSize)
+		copy(newBuf, b.buf)
+		b.buf = newBuf
+	}
+
+	b.idx = 0
+
+	for {
+		if b.timeout > 0 {
+			if err := b.nc.SetReadDeadline(time.Now().Add(b.timeout)); err != nil {
+				return err
+			}
+		}
+
+		nn, err := b.nc.Read(b.buf[n:])
+		n += nn
+
+		switch err {
+		case nil:
+			if n < need {
+				continue
+			}
+			b.length = n
+			return nil
+
+		case io.EOF:
+			if n >= need {
+				b.length = n
+				return nil
+			}
+			return io.ErrUnexpectedEOF
+
+		default:
+			return err
+		}
+	}
+}
+
+// returns next N bytes from buffer.
+// The returned slice is only guaranteed to be valid until the next read
+func (b *buffer) readNext(need int) ([]byte, error) {
+	if b.length < need {
+		// refill
+		if err := b.fill(need); err != nil {
+			return nil, err
+		}
+	}
+
+	offset := b.idx
+	b.idx += need
+	b.length -= need
+	return b.buf[offset:b.idx], nil
+}
+
+// returns a buffer with the requested size.
+// If possible, a slice from the existing buffer is returned.
+// Otherwise a bigger buffer is made.
+// Only one buffer (total) can be used at a time.
+func (b *buffer) takeBuffer(length int) []byte {
+	if b.length > 0 {
+		return nil
+	}
+
+	// test (cheap) general case first
+	if length <= defaultBufSize || length <= cap(b.buf) {
+		return b.buf[:length]
+	}
+
+	if length < maxPacketSize {
+		b.buf = make([]byte, length)
+		return b.buf
+	}
+	return make([]byte, length)
+}
+
+// shortcut which can be used if the requested buffer is guaranteed to be
+// smaller than defaultBufSize
+// Only one buffer (total) can be used at a time.
+func (b *buffer) takeSmallBuffer(length int) []byte {
+	if b.length == 0 {
+		return b.buf[:length]
+	}
+	return nil
+}
+
+// takeCompleteBuffer returns the complete existing buffer.
+// This can be used if the necessary buffer size is unknown.
+// Only one buffer (total) can be used at a time.
+func (b *buffer) takeCompleteBuffer() []byte {
+	if b.length == 0 {
+		return b.buf
+	}
+	return nil
+}

+ 250 - 0
vendor/github.com/go-sql-driver/mysql/collations.go

@@ -0,0 +1,250 @@
+// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
+//
+// Copyright 2014 The Go-MySQL-Driver Authors. All rights reserved.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package mysql
+
+const defaultCollation = "utf8_general_ci"
+
+// A list of available collations mapped to the internal ID.
+// To update this map use the following MySQL query:
+//     SELECT COLLATION_NAME, ID FROM information_schema.COLLATIONS
+var collations = map[string]byte{
+	"big5_chinese_ci":          1,
+	"latin2_czech_cs":          2,
+	"dec8_swedish_ci":          3,
+	"cp850_general_ci":         4,
+	"latin1_german1_ci":        5,
+	"hp8_english_ci":           6,
+	"koi8r_general_ci":         7,
+	"latin1_swedish_ci":        8,
+	"latin2_general_ci":        9,
+	"swe7_swedish_ci":          10,
+	"ascii_general_ci":         11,
+	"ujis_japanese_ci":         12,
+	"sjis_japanese_ci":         13,
+	"cp1251_bulgarian_ci":      14,
+	"latin1_danish_ci":         15,
+	"hebrew_general_ci":        16,
+	"tis620_thai_ci":           18,
+	"euckr_korean_ci":          19,
+	"latin7_estonian_cs":       20,
+	"latin2_hungarian_ci":      21,
+	"koi8u_general_ci":         22,
+	"cp1251_ukrainian_ci":      23,
+	"gb2312_chinese_ci":        24,
+	"greek_general_ci":         25,
+	"cp1250_general_ci":        26,
+	"latin2_croatian_ci":       27,
+	"gbk_chinese_ci":           28,
+	"cp1257_lithuanian_ci":     29,
+	"latin5_turkish_ci":        30,
+	"latin1_german2_ci":        31,
+	"armscii8_general_ci":      32,
+	"utf8_general_ci":          33,
+	"cp1250_czech_cs":          34,
+	"ucs2_general_ci":          35,
+	"cp866_general_ci":         36,
+	"keybcs2_general_ci":       37,
+	"macce_general_ci":         38,
+	"macroman_general_ci":      39,
+	"cp852_general_ci":         40,
+	"latin7_general_ci":        41,
+	"latin7_general_cs":        42,
+	"macce_bin":                43,
+	"cp1250_croatian_ci":       44,
+	"utf8mb4_general_ci":       45,
+	"utf8mb4_bin":              46,
+	"latin1_bin":               47,
+	"latin1_general_ci":        48,
+	"latin1_general_cs":        49,
+	"cp1251_bin":               50,
+	"cp1251_general_ci":        51,
+	"cp1251_general_cs":        52,
+	"macroman_bin":             53,
+	"utf16_general_ci":         54,
+	"utf16_bin":                55,
+	"utf16le_general_ci":       56,
+	"cp1256_general_ci":        57,
+	"cp1257_bin":               58,
+	"cp1257_general_ci":        59,
+	"utf32_general_ci":         60,
+	"utf32_bin":                61,
+	"utf16le_bin":              62,
+	"binary":                   63,
+	"armscii8_bin":             64,
+	"ascii_bin":                65,
+	"cp1250_bin":               66,
+	"cp1256_bin":               67,
+	"cp866_bin":                68,
+	"dec8_bin":                 69,
+	"greek_bin":                70,
+	"hebrew_bin":               71,
+	"hp8_bin":                  72,
+	"keybcs2_bin":              73,
+	"koi8r_bin":                74,
+	"koi8u_bin":                75,
+	"latin2_bin":               77,
+	"latin5_bin":               78,
+	"latin7_bin":               79,
+	"cp850_bin":                80,
+	"cp852_bin":                81,
+	"swe7_bin":                 82,
+	"utf8_bin":                 83,
+	"big5_bin":                 84,
+	"euckr_bin":                85,
+	"gb2312_bin":               86,
+	"gbk_bin":                  87,
+	"sjis_bin":                 88,
+	"tis620_bin":               89,
+	"ucs2_bin":                 90,
+	"ujis_bin":                 91,
+	"geostd8_general_ci":       92,
+	"geostd8_bin":              93,
+	"latin1_spanish_ci":        94,
+	"cp932_japanese_ci":        95,
+	"cp932_bin":                96,
+	"eucjpms_japanese_ci":      97,
+	"eucjpms_bin":              98,
+	"cp1250_polish_ci":         99,
+	"utf16_unicode_ci":         101,
+	"utf16_icelandic_ci":       102,
+	"utf16_latvian_ci":         103,
+	"utf16_romanian_ci":        104,
+	"utf16_slovenian_ci":       105,
+	"utf16_polish_ci":          106,
+	"utf16_estonian_ci":        107,
+	"utf16_spanish_ci":         108,
+	"utf16_swedish_ci":         109,
+	"utf16_turkish_ci":         110,
+	"utf16_czech_ci":           111,
+	"utf16_danish_ci":          112,
+	"utf16_lithuanian_ci":      113,
+	"utf16_slovak_ci":          114,
+	"utf16_spanish2_ci":        115,
+	"utf16_roman_ci":           116,
+	"utf16_persian_ci":         117,
+	"utf16_esperanto_ci":       118,
+	"utf16_hungarian_ci":       119,
+	"utf16_sinhala_ci":         120,
+	"utf16_german2_ci":         121,
+	"utf16_croatian_ci":        122,
+	"utf16_unicode_520_ci":     123,
+	"utf16_vietnamese_ci":      124,
+	"ucs2_unicode_ci":          128,
+	"ucs2_icelandic_ci":        129,
+	"ucs2_latvian_ci":          130,
+	"ucs2_romanian_ci":         131,
+	"ucs2_slovenian_ci":        132,
+	"ucs2_polish_ci":           133,
+	"ucs2_estonian_ci":         134,
+	"ucs2_spanish_ci":          135,
+	"ucs2_swedish_ci":          136,
+	"ucs2_turkish_ci":          137,
+	"ucs2_czech_ci":            138,
+	"ucs2_danish_ci":           139,
+	"ucs2_lithuanian_ci":       140,
+	"ucs2_slovak_ci":           141,
+	"ucs2_spanish2_ci":         142,
+	"ucs2_roman_ci":            143,
+	"ucs2_persian_ci":          144,
+	"ucs2_esperanto_ci":        145,
+	"ucs2_hungarian_ci":        146,
+	"ucs2_sinhala_ci":          147,
+	"ucs2_german2_ci":          148,
+	"ucs2_croatian_ci":         149,
+	"ucs2_unicode_520_ci":      150,
+	"ucs2_vietnamese_ci":       151,
+	"ucs2_general_mysql500_ci": 159,
+	"utf32_unicode_ci":         160,
+	"utf32_icelandic_ci":       161,
+	"utf32_latvian_ci":         162,
+	"utf32_romanian_ci":        163,
+	"utf32_slovenian_ci":       164,
+	"utf32_polish_ci":          165,
+	"utf32_estonian_ci":        166,
+	"utf32_spanish_ci":         167,
+	"utf32_swedish_ci":         168,
+	"utf32_turkish_ci":         169,
+	"utf32_czech_ci":           170,
+	"utf32_danish_ci":          171,
+	"utf32_lithuanian_ci":      172,
+	"utf32_slovak_ci":          173,
+	"utf32_spanish2_ci":        174,
+	"utf32_roman_ci":           175,
+	"utf32_persian_ci":         176,
+	"utf32_esperanto_ci":       177,
+	"utf32_hungarian_ci":       178,
+	"utf32_sinhala_ci":         179,
+	"utf32_german2_ci":         180,
+	"utf32_croatian_ci":        181,
+	"utf32_unicode_520_ci":     182,
+	"utf32_vietnamese_ci":      183,
+	"utf8_unicode_ci":          192,
+	"utf8_icelandic_ci":        193,
+	"utf8_latvian_ci":          194,
+	"utf8_romanian_ci":         195,
+	"utf8_slovenian_ci":        196,
+	"utf8_polish_ci":           197,
+	"utf8_estonian_ci":         198,
+	"utf8_spanish_ci":          199,
+	"utf8_swedish_ci":          200,
+	"utf8_turkish_ci":          201,
+	"utf8_czech_ci":            202,
+	"utf8_danish_ci":           203,
+	"utf8_lithuanian_ci":       204,
+	"utf8_slovak_ci":           205,
+	"utf8_spanish2_ci":         206,
+	"utf8_roman_ci":            207,
+	"utf8_persian_ci":          208,
+	"utf8_esperanto_ci":        209,
+	"utf8_hungarian_ci":        210,
+	"utf8_sinhala_ci":          211,
+	"utf8_german2_ci":          212,
+	"utf8_croatian_ci":         213,
+	"utf8_unicode_520_ci":      214,
+	"utf8_vietnamese_ci":       215,
+	"utf8_general_mysql500_ci": 223,
+	"utf8mb4_unicode_ci":       224,
+	"utf8mb4_icelandic_ci":     225,
+	"utf8mb4_latvian_ci":       226,
+	"utf8mb4_romanian_ci":      227,
+	"utf8mb4_slovenian_ci":     228,
+	"utf8mb4_polish_ci":        229,
+	"utf8mb4_estonian_ci":      230,
+	"utf8mb4_spanish_ci":       231,
+	"utf8mb4_swedish_ci":       232,
+	"utf8mb4_turkish_ci":       233,
+	"utf8mb4_czech_ci":         234,
+	"utf8mb4_danish_ci":        235,
+	"utf8mb4_lithuanian_ci":    236,
+	"utf8mb4_slovak_ci":        237,
+	"utf8mb4_spanish2_ci":      238,
+	"utf8mb4_roman_ci":         239,
+	"utf8mb4_persian_ci":       240,
+	"utf8mb4_esperanto_ci":     241,
+	"utf8mb4_hungarian_ci":     242,
+	"utf8mb4_sinhala_ci":       243,
+	"utf8mb4_german2_ci":       244,
+	"utf8mb4_croatian_ci":      245,
+	"utf8mb4_unicode_520_ci":   246,
+	"utf8mb4_vietnamese_ci":    247,
+}
+
+// A blacklist of collations which is unsafe to interpolate parameters.
+// These multibyte encodings may contains 0x5c (`\`) in their trailing bytes.
+var unsafeCollations = map[string]bool{
+	"big5_chinese_ci":   true,
+	"sjis_japanese_ci":  true,
+	"gbk_chinese_ci":    true,
+	"big5_bin":          true,
+	"gb2312_bin":        true,
+	"gbk_bin":           true,
+	"sjis_bin":          true,
+	"cp932_japanese_ci": true,
+	"cp932_bin":         true,
+}

+ 372 - 0
vendor/github.com/go-sql-driver/mysql/connection.go

@@ -0,0 +1,372 @@
+// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
+//
+// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package mysql
+
+import (
+	"database/sql/driver"
+	"net"
+	"strconv"
+	"strings"
+	"time"
+)
+
+type mysqlConn struct {
+	buf              buffer
+	netConn          net.Conn
+	affectedRows     uint64
+	insertId         uint64
+	cfg              *Config
+	maxPacketAllowed int
+	maxWriteSize     int
+	writeTimeout     time.Duration
+	flags            clientFlag
+	status           statusFlag
+	sequence         uint8
+	parseTime        bool
+	strict           bool
+}
+
+// Handles parameters set in DSN after the connection is established
+func (mc *mysqlConn) handleParams() (err error) {
+	for param, val := range mc.cfg.Params {
+		switch param {
+		// Charset
+		case "charset":
+			charsets := strings.Split(val, ",")
+			for i := range charsets {
+				// ignore errors here - a charset may not exist
+				err = mc.exec("SET NAMES " + charsets[i])
+				if err == nil {
+					break
+				}
+			}
+			if err != nil {
+				return
+			}
+
+		// System Vars
+		default:
+			err = mc.exec("SET " + param + "=" + val + "")
+			if err != nil {
+				return
+			}
+		}
+	}
+
+	return
+}
+
+func (mc *mysqlConn) Begin() (driver.Tx, error) {
+	if mc.netConn == nil {
+		errLog.Print(ErrInvalidConn)
+		return nil, driver.ErrBadConn
+	}
+	err := mc.exec("START TRANSACTION")
+	if err == nil {
+		return &mysqlTx{mc}, err
+	}
+
+	return nil, err
+}
+
+func (mc *mysqlConn) Close() (err error) {
+	// Makes Close idempotent
+	if mc.netConn != nil {
+		err = mc.writeCommandPacket(comQuit)
+	}
+
+	mc.cleanup()
+
+	return
+}
+
+// Closes the network connection and unsets internal variables. Do not call this
+// function after successfully authentication, call Close instead. This function
+// is called before auth or on auth failure because MySQL will have already
+// closed the network connection.
+func (mc *mysqlConn) cleanup() {
+	// Makes cleanup idempotent
+	if mc.netConn != nil {
+		if err := mc.netConn.Close(); err != nil {
+			errLog.Print(err)
+		}
+		mc.netConn = nil
+	}
+	mc.cfg = nil
+	mc.buf.nc = nil
+}
+
+func (mc *mysqlConn) Prepare(query string) (driver.Stmt, error) {
+	if mc.netConn == nil {
+		errLog.Print(ErrInvalidConn)
+		return nil, driver.ErrBadConn
+	}
+	// Send command
+	err := mc.writeCommandPacketStr(comStmtPrepare, query)
+	if err != nil {
+		return nil, err
+	}
+
+	stmt := &mysqlStmt{
+		mc: mc,
+	}
+
+	// Read Result
+	columnCount, err := stmt.readPrepareResultPacket()
+	if err == nil {
+		if stmt.paramCount > 0 {
+			if err = mc.readUntilEOF(); err != nil {
+				return nil, err
+			}
+		}
+
+		if columnCount > 0 {
+			err = mc.readUntilEOF()
+		}
+	}
+
+	return stmt, err
+}
+
+func (mc *mysqlConn) interpolateParams(query string, args []driver.Value) (string, error) {
+	buf := mc.buf.takeCompleteBuffer()
+	if buf == nil {
+		// can not take the buffer. Something must be wrong with the connection
+		errLog.Print(ErrBusyBuffer)
+		return "", driver.ErrBadConn
+	}
+	buf = buf[:0]
+	argPos := 0
+
+	for i := 0; i < len(query); i++ {
+		q := strings.IndexByte(query[i:], '?')
+		if q == -1 {
+			buf = append(buf, query[i:]...)
+			break
+		}
+		buf = append(buf, query[i:i+q]...)
+		i += q
+
+		arg := args[argPos]
+		argPos++
+
+		if arg == nil {
+			buf = append(buf, "NULL"...)
+			continue
+		}
+
+		switch v := arg.(type) {
+		case int64:
+			buf = strconv.AppendInt(buf, v, 10)
+		case float64:
+			buf = strconv.AppendFloat(buf, v, 'g', -1, 64)
+		case bool:
+			if v {
+				buf = append(buf, '1')
+			} else {
+				buf = append(buf, '0')
+			}
+		case time.Time:
+			if v.IsZero() {
+				buf = append(buf, "'0000-00-00'"...)
+			} else {
+				v := v.In(mc.cfg.Loc)
+				v = v.Add(time.Nanosecond * 500) // To round under microsecond
+				year := v.Year()
+				year100 := year / 100
+				year1 := year % 100
+				month := v.Month()
+				day := v.Day()
+				hour := v.Hour()
+				minute := v.Minute()
+				second := v.Second()
+				micro := v.Nanosecond() / 1000
+
+				buf = append(buf, []byte{
+					'\'',
+					digits10[year100], digits01[year100],
+					digits10[year1], digits01[year1],
+					'-',
+					digits10[month], digits01[month],
+					'-',
+					digits10[day], digits01[day],
+					' ',
+					digits10[hour], digits01[hour],
+					':',
+					digits10[minute], digits01[minute],
+					':',
+					digits10[second], digits01[second],
+				}...)
+
+				if micro != 0 {
+					micro10000 := micro / 10000
+					micro100 := micro / 100 % 100
+					micro1 := micro % 100
+					buf = append(buf, []byte{
+						'.',
+						digits10[micro10000], digits01[micro10000],
+						digits10[micro100], digits01[micro100],
+						digits10[micro1], digits01[micro1],
+					}...)
+				}
+				buf = append(buf, '\'')
+			}
+		case []byte:
+			if v == nil {
+				buf = append(buf, "NULL"...)
+			} else {
+				buf = append(buf, "_binary'"...)
+				if mc.status&statusNoBackslashEscapes == 0 {
+					buf = escapeBytesBackslash(buf, v)
+				} else {
+					buf = escapeBytesQuotes(buf, v)
+				}
+				buf = append(buf, '\'')
+			}
+		case string:
+			buf = append(buf, '\'')
+			if mc.status&statusNoBackslashEscapes == 0 {
+				buf = escapeStringBackslash(buf, v)
+			} else {
+				buf = escapeStringQuotes(buf, v)
+			}
+			buf = append(buf, '\'')
+		default:
+			return "", driver.ErrSkip
+		}
+
+		if len(buf)+4 > mc.maxPacketAllowed {
+			return "", driver.ErrSkip
+		}
+	}
+	if argPos != len(args) {
+		return "", driver.ErrSkip
+	}
+	return string(buf), nil
+}
+
+func (mc *mysqlConn) Exec(query string, args []driver.Value) (driver.Result, error) {
+	if mc.netConn == nil {
+		errLog.Print(ErrInvalidConn)
+		return nil, driver.ErrBadConn
+	}
+	if len(args) != 0 {
+		if !mc.cfg.InterpolateParams {
+			return nil, driver.ErrSkip
+		}
+		// try to interpolate the parameters to save extra roundtrips for preparing and closing a statement
+		prepared, err := mc.interpolateParams(query, args)
+		if err != nil {
+			return nil, err
+		}
+		query = prepared
+		args = nil
+	}
+	mc.affectedRows = 0
+	mc.insertId = 0
+
+	err := mc.exec(query)
+	if err == nil {
+		return &mysqlResult{
+			affectedRows: int64(mc.affectedRows),
+			insertId:     int64(mc.insertId),
+		}, err
+	}
+	return nil, err
+}
+
+// Internal function to execute commands
+func (mc *mysqlConn) exec(query string) error {
+	// Send command
+	err := mc.writeCommandPacketStr(comQuery, query)
+	if err != nil {
+		return err
+	}
+
+	// Read Result
+	resLen, err := mc.readResultSetHeaderPacket()
+	if err == nil && resLen > 0 {
+		if err = mc.readUntilEOF(); err != nil {
+			return err
+		}
+
+		err = mc.readUntilEOF()
+	}
+
+	return err
+}
+
+func (mc *mysqlConn) Query(query string, args []driver.Value) (driver.Rows, error) {
+	if mc.netConn == nil {
+		errLog.Print(ErrInvalidConn)
+		return nil, driver.ErrBadConn
+	}
+	if len(args) != 0 {
+		if !mc.cfg.InterpolateParams {
+			return nil, driver.ErrSkip
+		}
+		// try client-side prepare to reduce roundtrip
+		prepared, err := mc.interpolateParams(query, args)
+		if err != nil {
+			return nil, err
+		}
+		query = prepared
+		args = nil
+	}
+	// Send command
+	err := mc.writeCommandPacketStr(comQuery, query)
+	if err == nil {
+		// Read Result
+		var resLen int
+		resLen, err = mc.readResultSetHeaderPacket()
+		if err == nil {
+			rows := new(textRows)
+			rows.mc = mc
+
+			if resLen == 0 {
+				// no columns, no more data
+				return emptyRows{}, nil
+			}
+			// Columns
+			rows.columns, err = mc.readColumns(resLen)
+			return rows, err
+		}
+	}
+	return nil, err
+}
+
+// Gets the value of the given MySQL System Variable
+// The returned byte slice is only valid until the next read
+func (mc *mysqlConn) getSystemVar(name string) ([]byte, error) {
+	// Send command
+	if err := mc.writeCommandPacketStr(comQuery, "SELECT @@"+name); err != nil {
+		return nil, err
+	}
+
+	// Read Result
+	resLen, err := mc.readResultSetHeaderPacket()
+	if err == nil {
+		rows := new(textRows)
+		rows.mc = mc
+		rows.columns = []mysqlField{{fieldType: fieldTypeVarChar}}
+
+		if resLen > 0 {
+			// Columns
+			if err := mc.readUntilEOF(); err != nil {
+				return nil, err
+			}
+		}
+
+		dest := make([]driver.Value, resLen)
+		if err = rows.readRow(dest); err == nil {
+			return dest[0].([]byte), mc.readUntilEOF()
+		}
+	}
+	return nil, err
+}

+ 0 - 0
vendor/github.com/go-sql-driver/mysql/const.go


Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels