Browse Source

using glide

fatedier 7 years ago
parent
commit
0f1005ff61
100 changed files with 17553 additions and 158 deletions
  1. 0 158
      Godeps/Godeps.json
  2. 75 0
      glide.lock
  3. 73 0
      glide.yaml
  4. 119 0
      vendor/github.com/armon/go-socks5/auth_test.go
  5. 24 0
      vendor/github.com/armon/go-socks5/credentials_test.go
  6. 169 0
      vendor/github.com/armon/go-socks5/request_test.go
  7. 21 0
      vendor/github.com/armon/go-socks5/resolver_test.go
  8. 24 0
      vendor/github.com/armon/go-socks5/ruleset_test.go
  9. 110 0
      vendor/github.com/armon/go-socks5/socks5_test.go
  10. 22 0
      vendor/github.com/davecgh/go-spew/.gitignore
  11. 14 0
      vendor/github.com/davecgh/go-spew/.travis.yml
  12. 205 0
      vendor/github.com/davecgh/go-spew/README.md
  13. 22 0
      vendor/github.com/davecgh/go-spew/cov_report.sh
  14. 298 0
      vendor/github.com/davecgh/go-spew/spew/common_test.go
  15. 1042 0
      vendor/github.com/davecgh/go-spew/spew/dump_test.go
  16. 99 0
      vendor/github.com/davecgh/go-spew/spew/dumpcgo_test.go
  17. 26 0
      vendor/github.com/davecgh/go-spew/spew/dumpnocgo_test.go
  18. 226 0
      vendor/github.com/davecgh/go-spew/spew/example_test.go
  19. 1558 0
      vendor/github.com/davecgh/go-spew/spew/format_test.go
  20. 87 0
      vendor/github.com/davecgh/go-spew/spew/internal_test.go
  21. 102 0
      vendor/github.com/davecgh/go-spew/spew/internalunsafe_test.go
  22. 320 0
      vendor/github.com/davecgh/go-spew/spew/spew_test.go
  23. 82 0
      vendor/github.com/davecgh/go-spew/spew/testdata/dumpcgo.go
  24. 61 0
      vendor/github.com/davecgh/go-spew/test_coverage.txt
  25. 1536 0
      vendor/github.com/docopt/docopt-go/docopt_test.go
  26. 37 0
      vendor/github.com/docopt/docopt-go/example_test.go
  27. 29 0
      vendor/github.com/docopt/docopt-go/examples/arguments/arguments_example.go
  28. 26 0
      vendor/github.com/docopt/docopt-go/examples/calculator/calculator_example.go
  29. 76 0
      vendor/github.com/docopt/docopt-go/examples/config_file/config_file_example.go
  30. 22 0
      vendor/github.com/docopt/docopt-go/examples/counted/counted_example.go
  31. 38 0
      vendor/github.com/docopt/docopt-go/examples/git/branch/git_branch.go
  32. 30 0
      vendor/github.com/docopt/docopt-go/examples/git/checkout/git_checkout.go
  33. 37 0
      vendor/github.com/docopt/docopt-go/examples/git/clone/git_clone.go
  34. 108 0
      vendor/github.com/docopt/docopt-go/examples/git/git.go
  35. 34 0
      vendor/github.com/docopt/docopt-go/examples/git/push/git_push.go
  36. 28 0
      vendor/github.com/docopt/docopt-go/examples/git/remote/git_remote.go
  37. 28 0
      vendor/github.com/docopt/docopt-go/examples/naval_fate/naval_fate.go
  38. 19 0
      vendor/github.com/docopt/docopt-go/examples/odd_even/odd_even_example.go
  39. 43 0
      vendor/github.com/docopt/docopt-go/examples/options/options_example.go
  40. 24 0
      vendor/github.com/docopt/docopt-go/examples/options_shortcut/options_shortcut_example.go
  41. 16 0
      vendor/github.com/docopt/docopt-go/examples/quick/quick_example.go
  42. 31 0
      vendor/github.com/docopt/docopt-go/examples/type_assert/type_assert_example.go
  43. 17 0
      vendor/github.com/fatedier/beego/.github/ISSUE_TEMPLATE
  44. 6 0
      vendor/github.com/fatedier/beego/.gitignore
  45. 51 0
      vendor/github.com/fatedier/beego/.travis.yml
  46. 52 0
      vendor/github.com/fatedier/beego/CONTRIBUTING.md
  47. 62 0
      vendor/github.com/fatedier/beego/README.md
  48. 401 0
      vendor/github.com/fatedier/beego/admin.go
  49. 73 0
      vendor/github.com/fatedier/beego/admin_test.go
  50. 286 0
      vendor/github.com/fatedier/beego/adminui.go
  51. 366 0
      vendor/github.com/fatedier/beego/app.go
  52. 100 0
      vendor/github.com/fatedier/beego/beego.go
  53. 59 0
      vendor/github.com/fatedier/beego/cache/README.md
  54. 103 0
      vendor/github.com/fatedier/beego/cache/cache.go
  55. 168 0
      vendor/github.com/fatedier/beego/cache/cache_test.go
  56. 100 0
      vendor/github.com/fatedier/beego/cache/conv.go
  57. 143 0
      vendor/github.com/fatedier/beego/cache/conv_test.go
  58. 255 0
      vendor/github.com/fatedier/beego/cache/file.go
  59. 191 0
      vendor/github.com/fatedier/beego/cache/memcache/memcache.go
  60. 108 0
      vendor/github.com/fatedier/beego/cache/memcache/memcache_test.go
  61. 244 0
      vendor/github.com/fatedier/beego/cache/memory.go
  62. 240 0
      vendor/github.com/fatedier/beego/cache/redis/redis.go
  63. 106 0
      vendor/github.com/fatedier/beego/cache/redis/redis_test.go
  64. 240 0
      vendor/github.com/fatedier/beego/cache/ssdb/ssdb.go
  65. 104 0
      vendor/github.com/fatedier/beego/cache/ssdb/ssdb_test.go
  66. 489 0
      vendor/github.com/fatedier/beego/config.go
  67. 242 0
      vendor/github.com/fatedier/beego/config/config.go
  68. 55 0
      vendor/github.com/fatedier/beego/config/config_test.go
  69. 85 0
      vendor/github.com/fatedier/beego/config/env/env.go
  70. 75 0
      vendor/github.com/fatedier/beego/config/env/env_test.go
  71. 134 0
      vendor/github.com/fatedier/beego/config/fake.go
  72. 474 0
      vendor/github.com/fatedier/beego/config/ini.go
  73. 190 0
      vendor/github.com/fatedier/beego/config/ini_test.go
  74. 266 0
      vendor/github.com/fatedier/beego/config/json.go
  75. 222 0
      vendor/github.com/fatedier/beego/config/json_test.go
  76. 228 0
      vendor/github.com/fatedier/beego/config/xml/xml.go
  77. 125 0
      vendor/github.com/fatedier/beego/config/xml/xml_test.go
  78. 297 0
      vendor/github.com/fatedier/beego/config/yaml/yaml.go
  79. 115 0
      vendor/github.com/fatedier/beego/config/yaml/yaml_test.go
  80. 138 0
      vendor/github.com/fatedier/beego/config_test.go
  81. 231 0
      vendor/github.com/fatedier/beego/context/acceptencoder.go
  82. 59 0
      vendor/github.com/fatedier/beego/context/acceptencoder_test.go
  83. 230 0
      vendor/github.com/fatedier/beego/context/context.go
  84. 47 0
      vendor/github.com/fatedier/beego/context/context_test.go
  85. 650 0
      vendor/github.com/fatedier/beego/context/input.go
  86. 207 0
      vendor/github.com/fatedier/beego/context/input_test.go
  87. 350 0
      vendor/github.com/fatedier/beego/context/output.go
  88. 652 0
      vendor/github.com/fatedier/beego/controller.go
  89. 181 0
      vendor/github.com/fatedier/beego/controller_test.go
  90. 17 0
      vendor/github.com/fatedier/beego/doc.go
  91. 452 0
      vendor/github.com/fatedier/beego/error.go
  92. 88 0
      vendor/github.com/fatedier/beego/error_test.go
  93. 44 0
      vendor/github.com/fatedier/beego/filter.go
  94. 68 0
      vendor/github.com/fatedier/beego/filter_test.go
  95. 110 0
      vendor/github.com/fatedier/beego/flash.go
  96. 54 0
      vendor/github.com/fatedier/beego/flash_test.go
  97. 28 0
      vendor/github.com/fatedier/beego/grace/conn.go
  98. 166 0
      vendor/github.com/fatedier/beego/grace/grace.go
  99. 62 0
      vendor/github.com/fatedier/beego/grace/listener.go
  100. 306 0
      vendor/github.com/fatedier/beego/grace/server.go

+ 0 - 158
Godeps/Godeps.json

@@ -1,158 +0,0 @@
-{
-	"ImportPath": "github.com/fatedier/frp",
-	"GoVersion": "go1.9",
-	"GodepVersion": "v79",
-	"Packages": [
-		"./..."
-	],
-	"Deps": [
-		{
-			"ImportPath": "github.com/armon/go-socks5",
-			"Rev": "e75332964ef517daa070d7c38a9466a0d687e0a5"
-		},
-		{
-			"ImportPath": "github.com/davecgh/go-spew/spew",
-			"Comment": "v1.1.0",
-			"Rev": "346938d642f2ec3594ed81d874461961cd0faa76"
-		},
-		{
-			"ImportPath": "github.com/docopt/docopt-go",
-			"Comment": "0.6.2",
-			"Rev": "784ddc588536785e7299f7272f39101f7faccc3f"
-		},
-		{
-			"ImportPath": "github.com/fatedier/beego/logs",
-			"Comment": "v1.7.2-73-g6c6a4f5",
-			"Rev": "6c6a4f5bd5eb5a39f7e289b8f345b55f75e7e3e8"
-		},
-		{
-			"ImportPath": "github.com/fatedier/kcp-go",
-			"Comment": "v3.15-35-gcd167d2",
-			"Rev": "cd167d2f15f451b0f33780ce862fca97adc0331e"
-		},
-		{
-			"ImportPath": "github.com/golang/snappy",
-			"Rev": "5979233c5d6225d4a8e438cdd0b411888449ddab"
-		},
-		{
-			"ImportPath": "github.com/julienschmidt/httprouter",
-			"Comment": "v1.1-41-g8a45e95",
-			"Rev": "8a45e95fc75cb77048068a62daed98cc22fdac7c"
-		},
-		{
-			"ImportPath": "github.com/klauspost/cpuid",
-			"Comment": "v1.0",
-			"Rev": "09cded8978dc9e80714c4d85b0322337b0a1e5e0"
-		},
-		{
-			"ImportPath": "github.com/klauspost/reedsolomon",
-			"Comment": "1.3-1-gdde6ad5",
-			"Rev": "dde6ad55c5e5a6379a4e82dcca32ee407346eb6d"
-		},
-		{
-			"ImportPath": "github.com/pkg/errors",
-			"Comment": "v0.8.0-5-gc605e28",
-			"Rev": "c605e284fe17294bda444b34710735b29d1a9d90"
-		},
-		{
-			"ImportPath": "github.com/pmezard/go-difflib/difflib",
-			"Comment": "v1.0.0",
-			"Rev": "792786c7400a136282c1664665ae0a8db921c6c2"
-		},
-		{
-			"ImportPath": "github.com/rakyll/statik/fs",
-			"Comment": "v0.1.0",
-			"Rev": "274df120e9065bdd08eb1120e0375e3dc1ae8465"
-		},
-		{
-			"ImportPath": "github.com/stretchr/testify/assert",
-			"Comment": "v1.1.4-25-g2402e8e",
-			"Rev": "2402e8e7a02fc811447d11f881aa9746cdc57983"
-		},
-		{
-			"ImportPath": "github.com/templexxx/cpufeat",
-			"Rev": "3794dfbfb04749f896b521032f69383f24c3687e"
-		},
-		{
-			"ImportPath": "github.com/templexxx/reedsolomon",
-			"Comment": "0.1.1-4-g7092926",
-			"Rev": "7092926d7d05c415fabb892b1464a03f8228ab80"
-		},
-		{
-			"ImportPath": "github.com/templexxx/xor",
-			"Comment": "0.1.2",
-			"Rev": "0af8e873c554da75f37f2049cdffda804533d44c"
-		},
-		{
-			"ImportPath": "github.com/tjfoc/gmsm/sm4",
-			"Comment": "v1.0-42-g21d76de",
-			"Rev": "21d76dee237dbbc8dfe1510000b9bf2733635aa1"
-		},
-		{
-			"ImportPath": "github.com/vaughan0/go-ini",
-			"Rev": "a98ad7ee00ec53921f08832bc06ecf7fd600e6a1"
-		},
-		{
-			"ImportPath": "github.com/xtaci/kcp-go",
-			"Comment": "v3.17",
-			"Rev": "df437e2b8ec365a336200f9d9da53441cf72ed47"
-		},
-		{
-			"ImportPath": "github.com/xtaci/smux",
-			"Comment": "v1.0.5-8-g2de5471",
-			"Rev": "2de5471dfcbc029f5fe1392b83fe784127c4943e"
-		},
-		{
-			"ImportPath": "golang.org/x/crypto/blowfish",
-			"Rev": "e1a4589e7d3ea14a3352255d04b6f1a418845e5e"
-		},
-		{
-			"ImportPath": "golang.org/x/crypto/cast5",
-			"Rev": "e1a4589e7d3ea14a3352255d04b6f1a418845e5e"
-		},
-		{
-			"ImportPath": "golang.org/x/crypto/pbkdf2",
-			"Rev": "e1a4589e7d3ea14a3352255d04b6f1a418845e5e"
-		},
-		{
-			"ImportPath": "golang.org/x/crypto/salsa20",
-			"Rev": "e1a4589e7d3ea14a3352255d04b6f1a418845e5e"
-		},
-		{
-			"ImportPath": "golang.org/x/crypto/salsa20/salsa",
-			"Rev": "e1a4589e7d3ea14a3352255d04b6f1a418845e5e"
-		},
-		{
-			"ImportPath": "golang.org/x/crypto/tea",
-			"Rev": "e1a4589e7d3ea14a3352255d04b6f1a418845e5e"
-		},
-		{
-			"ImportPath": "golang.org/x/crypto/twofish",
-			"Rev": "e1a4589e7d3ea14a3352255d04b6f1a418845e5e"
-		},
-		{
-			"ImportPath": "golang.org/x/crypto/xtea",
-			"Rev": "e1a4589e7d3ea14a3352255d04b6f1a418845e5e"
-		},
-		{
-			"ImportPath": "golang.org/x/net/bpf",
-			"Rev": "e4fa1c5465ad6111f206fc92186b8c83d64adbe1"
-		},
-		{
-			"ImportPath": "golang.org/x/net/context",
-			"Rev": "e4fa1c5465ad6111f206fc92186b8c83d64adbe1"
-		},
-		{
-			"ImportPath": "golang.org/x/net/internal/iana",
-			"Rev": "e4fa1c5465ad6111f206fc92186b8c83d64adbe1"
-		},
-		{
-			"ImportPath": "golang.org/x/net/internal/socket",
-			"Rev": "e4fa1c5465ad6111f206fc92186b8c83d64adbe1"
-		},
-		{
-			"ImportPath": "golang.org/x/net/ipv4",
-			"Rev": "e4fa1c5465ad6111f206fc92186b8c83d64adbe1"
-		}
-	]
-}

+ 75 - 0
glide.lock

@@ -0,0 +1,75 @@
+hash: 03ff8b71f63e9038c0182a4ef2a55aa9349782f4813c331e2d1f02f3dd15b4f8
+updated: 2017-11-01T16:16:18.577622991+08:00
+imports:
+- name: github.com/armon/go-socks5
+  version: e75332964ef517daa070d7c38a9466a0d687e0a5
+- name: github.com/davecgh/go-spew
+  version: 346938d642f2ec3594ed81d874461961cd0faa76
+  subpackages:
+  - spew
+- name: github.com/docopt/docopt-go
+  version: 784ddc588536785e7299f7272f39101f7faccc3f
+- name: github.com/fatedier/beego
+  version: 6c6a4f5bd5eb5a39f7e289b8f345b55f75e7e3e8
+  subpackages:
+  - logs
+- name: github.com/fatedier/kcp-go
+  version: cd167d2f15f451b0f33780ce862fca97adc0331e
+- name: github.com/golang/snappy
+  version: 5979233c5d6225d4a8e438cdd0b411888449ddab
+- name: github.com/julienschmidt/httprouter
+  version: 8a45e95fc75cb77048068a62daed98cc22fdac7c
+- name: github.com/klauspost/cpuid
+  version: 09cded8978dc9e80714c4d85b0322337b0a1e5e0
+- name: github.com/klauspost/reedsolomon
+  version: dde6ad55c5e5a6379a4e82dcca32ee407346eb6d
+- name: github.com/pkg/errors
+  version: c605e284fe17294bda444b34710735b29d1a9d90
+- name: github.com/pmezard/go-difflib
+  version: 792786c7400a136282c1664665ae0a8db921c6c2
+  subpackages:
+  - difflib
+- name: github.com/rakyll/statik
+  version: 274df120e9065bdd08eb1120e0375e3dc1ae8465
+  subpackages:
+  - fs
+- name: github.com/stretchr/testify
+  version: 2402e8e7a02fc811447d11f881aa9746cdc57983
+  subpackages:
+  - assert
+- name: github.com/templexxx/cpufeat
+  version: 3794dfbfb04749f896b521032f69383f24c3687e
+- name: github.com/templexxx/reedsolomon
+  version: 7092926d7d05c415fabb892b1464a03f8228ab80
+- name: github.com/templexxx/xor
+  version: 0af8e873c554da75f37f2049cdffda804533d44c
+- name: github.com/tjfoc/gmsm
+  version: 21d76dee237dbbc8dfe1510000b9bf2733635aa1
+  subpackages:
+  - sm4
+- name: github.com/vaughan0/go-ini
+  version: a98ad7ee00ec53921f08832bc06ecf7fd600e6a1
+- name: github.com/xtaci/kcp-go
+  version: df437e2b8ec365a336200f9d9da53441cf72ed47
+- name: github.com/xtaci/smux
+  version: 2de5471dfcbc029f5fe1392b83fe784127c4943e
+- name: golang.org/x/crypto
+  version: e1a4589e7d3ea14a3352255d04b6f1a418845e5e
+  subpackages:
+  - blowfish
+  - cast5
+  - pbkdf2
+  - salsa20
+  - salsa20/salsa
+  - tea
+  - twofish
+  - xtea
+- name: golang.org/x/net
+  version: e4fa1c5465ad6111f206fc92186b8c83d64adbe1
+  subpackages:
+  - bpf
+  - context
+  - internal/iana
+  - internal/socket
+  - ipv4
+testImports: []

+ 73 - 0
glide.yaml

@@ -0,0 +1,73 @@
+package: github.com/fatedier/frp
+import:
+- package: github.com/armon/go-socks5
+  version: e75332964ef517daa070d7c38a9466a0d687e0a5
+- package: github.com/davecgh/go-spew
+  version: v1.1.0
+  subpackages:
+  - spew
+- package: github.com/docopt/docopt-go
+  version: 0.6.2
+- package: github.com/fatedier/beego
+  version: 6c6a4f5bd5eb5a39f7e289b8f345b55f75e7e3e8
+  subpackages:
+  - logs
+- package: github.com/fatedier/kcp-go
+  version: cd167d2f15f451b0f33780ce862fca97adc0331e
+- package: github.com/golang/snappy
+  version: 5979233c5d6225d4a8e438cdd0b411888449ddab
+- package: github.com/julienschmidt/httprouter
+  version: 8a45e95fc75cb77048068a62daed98cc22fdac7c
+- package: github.com/klauspost/cpuid
+  version: v1.0
+- package: github.com/klauspost/reedsolomon
+  version: dde6ad55c5e5a6379a4e82dcca32ee407346eb6d
+- package: github.com/pkg/errors
+  version: c605e284fe17294bda444b34710735b29d1a9d90
+- package: github.com/pmezard/go-difflib
+  version: v1.0.0
+  subpackages:
+  - difflib
+- package: github.com/rakyll/statik
+  version: v0.1.0
+  subpackages:
+  - fs
+- package: github.com/stretchr/testify
+  version: 2402e8e7a02fc811447d11f881aa9746cdc57983
+  subpackages:
+  - assert
+- package: github.com/templexxx/cpufeat
+  version: 3794dfbfb04749f896b521032f69383f24c3687e
+- package: github.com/templexxx/reedsolomon
+  version: 7092926d7d05c415fabb892b1464a03f8228ab80
+- package: github.com/templexxx/xor
+  version: 0.1.2
+- package: github.com/tjfoc/gmsm
+  version: 21d76dee237dbbc8dfe1510000b9bf2733635aa1
+  subpackages:
+  - sm4
+- package: github.com/vaughan0/go-ini
+  version: a98ad7ee00ec53921f08832bc06ecf7fd600e6a1
+- package: github.com/xtaci/kcp-go
+  version: v3.17
+- package: github.com/xtaci/smux
+  version: 2de5471dfcbc029f5fe1392b83fe784127c4943e
+- package: golang.org/x/crypto
+  version: e1a4589e7d3ea14a3352255d04b6f1a418845e5e
+  subpackages:
+  - blowfish
+  - cast5
+  - pbkdf2
+  - salsa20
+  - salsa20/salsa
+  - tea
+  - twofish
+  - xtea
+- package: golang.org/x/net
+  version: e4fa1c5465ad6111f206fc92186b8c83d64adbe1
+  subpackages:
+  - bpf
+  - context
+  - internal/iana
+  - internal/socket
+  - ipv4

+ 119 - 0
vendor/github.com/armon/go-socks5/auth_test.go

@@ -0,0 +1,119 @@
+package socks5
+
+import (
+	"bytes"
+	"testing"
+)
+
+func TestNoAuth(t *testing.T) {
+	req := bytes.NewBuffer(nil)
+	req.Write([]byte{1, NoAuth})
+	var resp bytes.Buffer
+
+	s, _ := New(&Config{})
+	ctx, err := s.authenticate(&resp, req)
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	if ctx.Method != NoAuth {
+		t.Fatal("Invalid Context Method")
+	}
+
+	out := resp.Bytes()
+	if !bytes.Equal(out, []byte{socks5Version, NoAuth}) {
+		t.Fatalf("bad: %v", out)
+	}
+}
+
+func TestPasswordAuth_Valid(t *testing.T) {
+	req := bytes.NewBuffer(nil)
+	req.Write([]byte{2, NoAuth, UserPassAuth})
+	req.Write([]byte{1, 3, 'f', 'o', 'o', 3, 'b', 'a', 'r'})
+	var resp bytes.Buffer
+
+	cred := StaticCredentials{
+		"foo": "bar",
+	}
+
+	cator := UserPassAuthenticator{Credentials: cred}
+
+	s, _ := New(&Config{AuthMethods: []Authenticator{cator}})
+
+	ctx, err := s.authenticate(&resp, req)
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	if ctx.Method != UserPassAuth {
+		t.Fatal("Invalid Context Method")
+	}
+
+	val, ok := ctx.Payload["Username"]
+	if !ok {
+		t.Fatal("Missing key Username in auth context's payload")
+	}
+
+	if val != "foo" {
+		t.Fatal("Invalid Username in auth context's payload")
+	}
+
+	out := resp.Bytes()
+	if !bytes.Equal(out, []byte{socks5Version, UserPassAuth, 1, authSuccess}) {
+		t.Fatalf("bad: %v", out)
+	}
+}
+
+func TestPasswordAuth_Invalid(t *testing.T) {
+	req := bytes.NewBuffer(nil)
+	req.Write([]byte{2, NoAuth, UserPassAuth})
+	req.Write([]byte{1, 3, 'f', 'o', 'o', 3, 'b', 'a', 'z'})
+	var resp bytes.Buffer
+
+	cred := StaticCredentials{
+		"foo": "bar",
+	}
+	cator := UserPassAuthenticator{Credentials: cred}
+	s, _ := New(&Config{AuthMethods: []Authenticator{cator}})
+
+	ctx, err := s.authenticate(&resp, req)
+	if err != UserAuthFailed {
+		t.Fatalf("err: %v", err)
+	}
+
+	if ctx != nil {
+		t.Fatal("Invalid Context Method")
+	}
+
+	out := resp.Bytes()
+	if !bytes.Equal(out, []byte{socks5Version, UserPassAuth, 1, authFailure}) {
+		t.Fatalf("bad: %v", out)
+	}
+}
+
+func TestNoSupportedAuth(t *testing.T) {
+	req := bytes.NewBuffer(nil)
+	req.Write([]byte{1, NoAuth})
+	var resp bytes.Buffer
+
+	cred := StaticCredentials{
+		"foo": "bar",
+	}
+	cator := UserPassAuthenticator{Credentials: cred}
+
+	s, _ := New(&Config{AuthMethods: []Authenticator{cator}})
+
+	ctx, err := s.authenticate(&resp, req)
+	if err != NoSupportedAuth {
+		t.Fatalf("err: %v", err)
+	}
+
+	if ctx != nil {
+		t.Fatal("Invalid Context Method")
+	}
+
+	out := resp.Bytes()
+	if !bytes.Equal(out, []byte{socks5Version, noAcceptable}) {
+		t.Fatalf("bad: %v", out)
+	}
+}

+ 24 - 0
vendor/github.com/armon/go-socks5/credentials_test.go

@@ -0,0 +1,24 @@
+package socks5
+
+import (
+	"testing"
+)
+
+func TestStaticCredentials(t *testing.T) {
+	creds := StaticCredentials{
+		"foo": "bar",
+		"baz": "",
+	}
+
+	if !creds.Valid("foo", "bar") {
+		t.Fatalf("expect valid")
+	}
+
+	if !creds.Valid("baz", "") {
+		t.Fatalf("expect valid")
+	}
+
+	if creds.Valid("foo", "") {
+		t.Fatalf("expect invalid")
+	}
+}

+ 169 - 0
vendor/github.com/armon/go-socks5/request_test.go

@@ -0,0 +1,169 @@
+package socks5
+
+import (
+	"bytes"
+	"encoding/binary"
+	"io"
+	"log"
+	"net"
+	"os"
+	"strings"
+	"testing"
+)
+
+type MockConn struct {
+	buf bytes.Buffer
+}
+
+func (m *MockConn) Write(b []byte) (int, error) {
+	return m.buf.Write(b)
+}
+
+func (m *MockConn) RemoteAddr() net.Addr {
+	return &net.TCPAddr{IP: []byte{127, 0, 0, 1}, Port: 65432}
+}
+
+func TestRequest_Connect(t *testing.T) {
+	// Create a local listener
+	l, err := net.Listen("tcp", "127.0.0.1:0")
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+	go func() {
+		conn, err := l.Accept()
+		if err != nil {
+			t.Fatalf("err: %v", err)
+		}
+		defer conn.Close()
+
+		buf := make([]byte, 4)
+		if _, err := io.ReadAtLeast(conn, buf, 4); err != nil {
+			t.Fatalf("err: %v", err)
+		}
+
+		if !bytes.Equal(buf, []byte("ping")) {
+			t.Fatalf("bad: %v", buf)
+		}
+		conn.Write([]byte("pong"))
+	}()
+	lAddr := l.Addr().(*net.TCPAddr)
+
+	// Make server
+	s := &Server{config: &Config{
+		Rules:    PermitAll(),
+		Resolver: DNSResolver{},
+		Logger:   log.New(os.Stdout, "", log.LstdFlags),
+	}}
+
+	// Create the connect request
+	buf := bytes.NewBuffer(nil)
+	buf.Write([]byte{5, 1, 0, 1, 127, 0, 0, 1})
+
+	port := []byte{0, 0}
+	binary.BigEndian.PutUint16(port, uint16(lAddr.Port))
+	buf.Write(port)
+
+	// Send a ping
+	buf.Write([]byte("ping"))
+
+	// Handle the request
+	resp := &MockConn{}
+	req, err := NewRequest(buf)
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	if err := s.handleRequest(req, resp); err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	// Verify response
+	out := resp.buf.Bytes()
+	expected := []byte{
+		5,
+		0,
+		0,
+		1,
+		127, 0, 0, 1,
+		0, 0,
+		'p', 'o', 'n', 'g',
+	}
+
+	// Ignore the port for both
+	out[8] = 0
+	out[9] = 0
+
+	if !bytes.Equal(out, expected) {
+		t.Fatalf("bad: %v %v", out, expected)
+	}
+}
+
+func TestRequest_Connect_RuleFail(t *testing.T) {
+	// Create a local listener
+	l, err := net.Listen("tcp", "127.0.0.1:0")
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+	go func() {
+		conn, err := l.Accept()
+		if err != nil {
+			t.Fatalf("err: %v", err)
+		}
+		defer conn.Close()
+
+		buf := make([]byte, 4)
+		if _, err := io.ReadAtLeast(conn, buf, 4); err != nil {
+			t.Fatalf("err: %v", err)
+		}
+
+		if !bytes.Equal(buf, []byte("ping")) {
+			t.Fatalf("bad: %v", buf)
+		}
+		conn.Write([]byte("pong"))
+	}()
+	lAddr := l.Addr().(*net.TCPAddr)
+
+	// Make server
+	s := &Server{config: &Config{
+		Rules:    PermitNone(),
+		Resolver: DNSResolver{},
+		Logger:   log.New(os.Stdout, "", log.LstdFlags),
+	}}
+
+	// Create the connect request
+	buf := bytes.NewBuffer(nil)
+	buf.Write([]byte{5, 1, 0, 1, 127, 0, 0, 1})
+
+	port := []byte{0, 0}
+	binary.BigEndian.PutUint16(port, uint16(lAddr.Port))
+	buf.Write(port)
+
+	// Send a ping
+	buf.Write([]byte("ping"))
+
+	// Handle the request
+	resp := &MockConn{}
+	req, err := NewRequest(buf)
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	if err := s.handleRequest(req, resp); !strings.Contains(err.Error(), "blocked by rules") {
+		t.Fatalf("err: %v", err)
+	}
+
+	// Verify response
+	out := resp.buf.Bytes()
+	expected := []byte{
+		5,
+		2,
+		0,
+		1,
+		0, 0, 0, 0,
+		0, 0,
+	}
+
+	if !bytes.Equal(out, expected) {
+		t.Fatalf("bad: %v %v", out, expected)
+	}
+}

+ 21 - 0
vendor/github.com/armon/go-socks5/resolver_test.go

@@ -0,0 +1,21 @@
+package socks5
+
+import (
+	"testing"
+
+	"golang.org/x/net/context"
+)
+
+func TestDNSResolver(t *testing.T) {
+	d := DNSResolver{}
+	ctx := context.Background()
+
+	_, addr, err := d.Resolve(ctx, "localhost")
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	if !addr.IsLoopback() {
+		t.Fatalf("expected loopback")
+	}
+}

+ 24 - 0
vendor/github.com/armon/go-socks5/ruleset_test.go

@@ -0,0 +1,24 @@
+package socks5
+
+import (
+	"testing"
+
+	"golang.org/x/net/context"
+)
+
+func TestPermitCommand(t *testing.T) {
+	ctx := context.Background()
+	r := &PermitCommand{true, false, false}
+
+	if _, ok := r.Allow(ctx, &Request{Command: ConnectCommand}); !ok {
+		t.Fatalf("expect connect")
+	}
+
+	if _, ok := r.Allow(ctx, &Request{Command: BindCommand}); ok {
+		t.Fatalf("do not expect bind")
+	}
+
+	if _, ok := r.Allow(ctx, &Request{Command: AssociateCommand}); ok {
+		t.Fatalf("do not expect associate")
+	}
+}

+ 110 - 0
vendor/github.com/armon/go-socks5/socks5_test.go

@@ -0,0 +1,110 @@
+package socks5
+
+import (
+	"bytes"
+	"encoding/binary"
+	"io"
+	"log"
+	"net"
+	"os"
+	"testing"
+	"time"
+)
+
+func TestSOCKS5_Connect(t *testing.T) {
+	// Create a local listener
+	l, err := net.Listen("tcp", "127.0.0.1:0")
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+	go func() {
+		conn, err := l.Accept()
+		if err != nil {
+			t.Fatalf("err: %v", err)
+		}
+		defer conn.Close()
+
+		buf := make([]byte, 4)
+		if _, err := io.ReadAtLeast(conn, buf, 4); err != nil {
+			t.Fatalf("err: %v", err)
+		}
+
+		if !bytes.Equal(buf, []byte("ping")) {
+			t.Fatalf("bad: %v", buf)
+		}
+		conn.Write([]byte("pong"))
+	}()
+	lAddr := l.Addr().(*net.TCPAddr)
+
+	// Create a socks server
+	creds := StaticCredentials{
+		"foo": "bar",
+	}
+	cator := UserPassAuthenticator{Credentials: creds}
+	conf := &Config{
+		AuthMethods: []Authenticator{cator},
+		Logger:      log.New(os.Stdout, "", log.LstdFlags),
+	}
+	serv, err := New(conf)
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	// Start listening
+	go func() {
+		if err := serv.ListenAndServe("tcp", "127.0.0.1:12365"); err != nil {
+			t.Fatalf("err: %v", err)
+		}
+	}()
+	time.Sleep(10 * time.Millisecond)
+
+	// Get a local conn
+	conn, err := net.Dial("tcp", "127.0.0.1:12365")
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	// Connect, auth and connec to local
+	req := bytes.NewBuffer(nil)
+	req.Write([]byte{5})
+	req.Write([]byte{2, NoAuth, UserPassAuth})
+	req.Write([]byte{1, 3, 'f', 'o', 'o', 3, 'b', 'a', 'r'})
+	req.Write([]byte{5, 1, 0, 1, 127, 0, 0, 1})
+
+	port := []byte{0, 0}
+	binary.BigEndian.PutUint16(port, uint16(lAddr.Port))
+	req.Write(port)
+
+	// Send a ping
+	req.Write([]byte("ping"))
+
+	// Send all the bytes
+	conn.Write(req.Bytes())
+
+	// Verify response
+	expected := []byte{
+		socks5Version, UserPassAuth,
+		1, authSuccess,
+		5,
+		0,
+		0,
+		1,
+		127, 0, 0, 1,
+		0, 0,
+		'p', 'o', 'n', 'g',
+	}
+	out := make([]byte, len(expected))
+
+	conn.SetDeadline(time.Now().Add(time.Second))
+	if _, err := io.ReadAtLeast(conn, out, len(out)); err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	// Ignore the port
+	out[12] = 0
+	out[13] = 0
+
+	if !bytes.Equal(out, expected) {
+		t.Fatalf("bad: %v", out)
+	}
+}

+ 22 - 0
vendor/github.com/davecgh/go-spew/.gitignore

@@ -0,0 +1,22 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe

+ 14 - 0
vendor/github.com/davecgh/go-spew/.travis.yml

@@ -0,0 +1,14 @@
+language: go
+go:
+    - 1.5.4
+    - 1.6.3
+    - 1.7
+install:
+    - go get -v golang.org/x/tools/cmd/cover
+script:
+    - go test -v -tags=safe ./spew
+    - go test -v -tags=testcgo ./spew -covermode=count -coverprofile=profile.cov
+after_success:
+    - go get -v github.com/mattn/goveralls
+    - export PATH=$PATH:$HOME/gopath/bin
+    - goveralls -coverprofile=profile.cov -service=travis-ci

+ 205 - 0
vendor/github.com/davecgh/go-spew/README.md

@@ -0,0 +1,205 @@
+go-spew
+=======
+
+[![Build Status](https://img.shields.io/travis/davecgh/go-spew.svg)]
+(https://travis-ci.org/davecgh/go-spew) [![ISC License]
+(http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org) [![Coverage Status]
+(https://img.shields.io/coveralls/davecgh/go-spew.svg)]
+(https://coveralls.io/r/davecgh/go-spew?branch=master)
+
+
+Go-spew implements a deep pretty printer for Go data structures to aid in
+debugging.  A comprehensive suite of tests with 100% test coverage is provided
+to ensure proper functionality.  See `test_coverage.txt` for the gocov coverage
+report.  Go-spew is licensed under the liberal ISC license, so it may be used in
+open source or commercial projects.
+
+If you're interested in reading about how this package came to life and some
+of the challenges involved in providing a deep pretty printer, there is a blog
+post about it
+[here](https://web.archive.org/web/20160304013555/https://blog.cyphertite.com/go-spew-a-journey-into-dumping-go-data-structures/).
+
+## Documentation
+
+[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)]
+(http://godoc.org/github.com/davecgh/go-spew/spew)
+
+Full `go doc` style documentation for the project can be viewed online without
+installing this package by using the excellent GoDoc site here:
+http://godoc.org/github.com/davecgh/go-spew/spew
+
+You can also view the documentation locally once the package is installed with
+the `godoc` tool by running `godoc -http=":6060"` and pointing your browser to
+http://localhost:6060/pkg/github.com/davecgh/go-spew/spew
+
+## Installation
+
+```bash
+$ go get -u github.com/davecgh/go-spew/spew
+```
+
+## Quick Start
+
+Add this import line to the file you're working in:
+
+```Go
+import "github.com/davecgh/go-spew/spew"
+```
+
+To dump a variable with full newlines, indentation, type, and pointer
+information use Dump, Fdump, or Sdump:
+
+```Go
+spew.Dump(myVar1, myVar2, ...)
+spew.Fdump(someWriter, myVar1, myVar2, ...)
+str := spew.Sdump(myVar1, myVar2, ...)
+```
+
+Alternatively, if you would prefer to use format strings with a compacted inline
+printing style, use the convenience wrappers Printf, Fprintf, etc with %v (most
+compact), %+v (adds pointer addresses), %#v (adds types), or %#+v (adds types
+and pointer addresses): 
+
+```Go
+spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2)
+spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
+spew.Fprintf(someWriter, "myVar1: %v -- myVar2: %+v", myVar1, myVar2)
+spew.Fprintf(someWriter, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
+```
+
+## Debugging a Web Application Example
+
+Here is an example of how you can use `spew.Sdump()` to help debug a web application. Please be sure to wrap your output using the `html.EscapeString()` function for safety reasons. You should also only use this debugging technique in a development environment, never in production.
+
+```Go
+package main
+
+import (
+    "fmt"
+    "html"
+    "net/http"
+
+    "github.com/davecgh/go-spew/spew"
+)
+
+func handler(w http.ResponseWriter, r *http.Request) {
+    w.Header().Set("Content-Type", "text/html")
+    fmt.Fprintf(w, "Hi there, %s!", r.URL.Path[1:])
+    fmt.Fprintf(w, "<!--\n" + html.EscapeString(spew.Sdump(w)) + "\n-->")
+}
+
+func main() {
+    http.HandleFunc("/", handler)
+    http.ListenAndServe(":8080", nil)
+}
+```
+
+## Sample Dump Output
+
+```
+(main.Foo) {
+ unexportedField: (*main.Bar)(0xf84002e210)({
+  flag: (main.Flag) flagTwo,
+  data: (uintptr) <nil>
+ }),
+ ExportedField: (map[interface {}]interface {}) {
+  (string) "one": (bool) true
+ }
+}
+([]uint8) {
+ 00000000  11 12 13 14 15 16 17 18  19 1a 1b 1c 1d 1e 1f 20  |............... |
+ 00000010  21 22 23 24 25 26 27 28  29 2a 2b 2c 2d 2e 2f 30  |!"#$%&'()*+,-./0|
+ 00000020  31 32                                             |12|
+}
+```
+
+## Sample Formatter Output
+
+Double pointer to a uint8:
+```
+	  %v: <**>5
+	 %+v: <**>(0xf8400420d0->0xf8400420c8)5
+	 %#v: (**uint8)5
+	%#+v: (**uint8)(0xf8400420d0->0xf8400420c8)5
+```
+
+Pointer to circular struct with a uint8 field and a pointer to itself:
+```
+	  %v: <*>{1 <*><shown>}
+	 %+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)<shown>}
+	 %#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)<shown>}
+	%#+v: (*main.circular)(0xf84003e260){ui8:(uint8)1 c:(*main.circular)(0xf84003e260)<shown>}
+```
+
+## Configuration Options
+
+Configuration of spew is handled by fields in the ConfigState type. For
+convenience, all of the top-level functions use a global state available via the
+spew.Config global.
+
+It is also possible to create a ConfigState instance that provides methods
+equivalent to the top-level functions. This allows concurrent configuration
+options. See the ConfigState documentation for more details.
+
+```
+* Indent
+	String to use for each indentation level for Dump functions.
+	It is a single space by default.  A popular alternative is "\t".
+
+* MaxDepth
+	Maximum number of levels to descend into nested data structures.
+	There is no limit by default.
+
+* DisableMethods
+	Disables invocation of error and Stringer interface methods.
+	Method invocation is enabled by default.
+
+* DisablePointerMethods
+	Disables invocation of error and Stringer interface methods on types
+	which only accept pointer receivers from non-pointer variables.  This option
+	relies on access to the unsafe package, so it will not have any effect when
+	running in environments without access to the unsafe package such as Google
+	App Engine or with the "safe" build tag specified.
+	Pointer method invocation is enabled by default.
+
+* DisablePointerAddresses
+	DisablePointerAddresses specifies whether to disable the printing of
+	pointer addresses. This is useful when diffing data structures in tests.
+
+* DisableCapacities
+	DisableCapacities specifies whether to disable the printing of capacities
+	for arrays, slices, maps and channels. This is useful when diffing data
+	structures in tests.
+
+* ContinueOnMethod
+	Enables recursion into types after invoking error and Stringer interface
+	methods. Recursion after method invocation is disabled by default.
+
+* SortKeys
+	Specifies map keys should be sorted before being printed. Use
+	this to have a more deterministic, diffable output.  Note that
+	only native types (bool, int, uint, floats, uintptr and string)
+	and types which implement error or Stringer interfaces are supported,
+	with other types sorted according to the reflect.Value.String() output
+	which guarantees display stability.  Natural map order is used by
+	default.
+
+* SpewKeys
+	SpewKeys specifies that, as a last resort attempt, map keys should be
+	spewed to strings and sorted by those strings.  This is only considered
+	if SortKeys is true.
+
+```
+
+## Unsafe Package Dependency
+
+This package relies on the unsafe package to perform some of the more advanced
+features, however it also supports a "limited" mode which allows it to work in
+environments where the unsafe package is not available.  By default, it will
+operate in this mode on Google App Engine and when compiled with GopherJS.  The
+"safe" build tag may also be specified to force the package to build without
+using the unsafe package.
+
+## License
+
+Go-spew is licensed under the [copyfree](http://copyfree.org) ISC License.

+ 22 - 0
vendor/github.com/davecgh/go-spew/cov_report.sh

@@ -0,0 +1,22 @@
+#!/bin/sh
+
+# This script uses gocov to generate a test coverage report.
+# The gocov tool my be obtained with the following command:
+#   go get github.com/axw/gocov/gocov
+#
+# It will be installed to $GOPATH/bin, so ensure that location is in your $PATH.
+
+# Check for gocov.
+if ! type gocov >/dev/null 2>&1; then
+	echo >&2 "This script requires the gocov tool."
+	echo >&2 "You may obtain it with the following command:"
+	echo >&2 "go get github.com/axw/gocov/gocov"
+	exit 1
+fi
+
+# Only run the cgo tests if gcc is installed.
+if type gcc >/dev/null 2>&1; then
+	(cd spew && gocov test -tags testcgo | gocov report)
+else
+	(cd spew && gocov test | gocov report)
+fi

+ 298 - 0
vendor/github.com/davecgh/go-spew/spew/common_test.go

@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+package spew_test
+
+import (
+	"fmt"
+	"reflect"
+	"testing"
+
+	"github.com/davecgh/go-spew/spew"
+)
+
+// custom type to test Stinger interface on non-pointer receiver.
+type stringer string
+
+// String implements the Stringer interface for testing invocation of custom
+// stringers on types with non-pointer receivers.
+func (s stringer) String() string {
+	return "stringer " + string(s)
+}
+
+// custom type to test Stinger interface on pointer receiver.
+type pstringer string
+
+// String implements the Stringer interface for testing invocation of custom
+// stringers on types with only pointer receivers.
+func (s *pstringer) String() string {
+	return "stringer " + string(*s)
+}
+
+// xref1 and xref2 are cross referencing structs for testing circular reference
+// detection.
+type xref1 struct {
+	ps2 *xref2
+}
+type xref2 struct {
+	ps1 *xref1
+}
+
+// indirCir1, indirCir2, and indirCir3 are used to generate an indirect circular
+// reference for testing detection.
+type indirCir1 struct {
+	ps2 *indirCir2
+}
+type indirCir2 struct {
+	ps3 *indirCir3
+}
+type indirCir3 struct {
+	ps1 *indirCir1
+}
+
+// embed is used to test embedded structures.
+type embed struct {
+	a string
+}
+
+// embedwrap is used to test embedded structures.
+type embedwrap struct {
+	*embed
+	e *embed
+}
+
+// panicer is used to intentionally cause a panic for testing spew properly
+// handles them
+type panicer int
+
+func (p panicer) String() string {
+	panic("test panic")
+}
+
+// customError is used to test custom error interface invocation.
+type customError int
+
+func (e customError) Error() string {
+	return fmt.Sprintf("error: %d", int(e))
+}
+
+// stringizeWants converts a slice of wanted test output into a format suitable
+// for a test error message.
+func stringizeWants(wants []string) string {
+	s := ""
+	for i, want := range wants {
+		if i > 0 {
+			s += fmt.Sprintf("want%d: %s", i+1, want)
+		} else {
+			s += "want: " + want
+		}
+	}
+	return s
+}
+
+// testFailed returns whether or not a test failed by checking if the result
+// of the test is in the slice of wanted strings.
+func testFailed(result string, wants []string) bool {
+	for _, want := range wants {
+		if result == want {
+			return false
+		}
+	}
+	return true
+}
+
+type sortableStruct struct {
+	x int
+}
+
+func (ss sortableStruct) String() string {
+	return fmt.Sprintf("ss.%d", ss.x)
+}
+
+type unsortableStruct struct {
+	x int
+}
+
+type sortTestCase struct {
+	input    []reflect.Value
+	expected []reflect.Value
+}
+
+func helpTestSortValues(tests []sortTestCase, cs *spew.ConfigState, t *testing.T) {
+	getInterfaces := func(values []reflect.Value) []interface{} {
+		interfaces := []interface{}{}
+		for _, v := range values {
+			interfaces = append(interfaces, v.Interface())
+		}
+		return interfaces
+	}
+
+	for _, test := range tests {
+		spew.SortValues(test.input, cs)
+		// reflect.DeepEqual cannot really make sense of reflect.Value,
+		// probably because of all the pointer tricks. For instance,
+		// v(2.0) != v(2.0) on a 32-bits system. Turn them into interface{}
+		// instead.
+		input := getInterfaces(test.input)
+		expected := getInterfaces(test.expected)
+		if !reflect.DeepEqual(input, expected) {
+			t.Errorf("Sort mismatch:\n %v != %v", input, expected)
+		}
+	}
+}
+
+// TestSortValues ensures the sort functionality for relect.Value based sorting
+// works as intended.
+func TestSortValues(t *testing.T) {
+	v := reflect.ValueOf
+
+	a := v("a")
+	b := v("b")
+	c := v("c")
+	embedA := v(embed{"a"})
+	embedB := v(embed{"b"})
+	embedC := v(embed{"c"})
+	tests := []sortTestCase{
+		// No values.
+		{
+			[]reflect.Value{},
+			[]reflect.Value{},
+		},
+		// Bools.
+		{
+			[]reflect.Value{v(false), v(true), v(false)},
+			[]reflect.Value{v(false), v(false), v(true)},
+		},
+		// Ints.
+		{
+			[]reflect.Value{v(2), v(1), v(3)},
+			[]reflect.Value{v(1), v(2), v(3)},
+		},
+		// Uints.
+		{
+			[]reflect.Value{v(uint8(2)), v(uint8(1)), v(uint8(3))},
+			[]reflect.Value{v(uint8(1)), v(uint8(2)), v(uint8(3))},
+		},
+		// Floats.
+		{
+			[]reflect.Value{v(2.0), v(1.0), v(3.0)},
+			[]reflect.Value{v(1.0), v(2.0), v(3.0)},
+		},
+		// Strings.
+		{
+			[]reflect.Value{b, a, c},
+			[]reflect.Value{a, b, c},
+		},
+		// Array
+		{
+			[]reflect.Value{v([3]int{3, 2, 1}), v([3]int{1, 3, 2}), v([3]int{1, 2, 3})},
+			[]reflect.Value{v([3]int{1, 2, 3}), v([3]int{1, 3, 2}), v([3]int{3, 2, 1})},
+		},
+		// Uintptrs.
+		{
+			[]reflect.Value{v(uintptr(2)), v(uintptr(1)), v(uintptr(3))},
+			[]reflect.Value{v(uintptr(1)), v(uintptr(2)), v(uintptr(3))},
+		},
+		// SortableStructs.
+		{
+			// Note: not sorted - DisableMethods is set.
+			[]reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
+			[]reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
+		},
+		// UnsortableStructs.
+		{
+			// Note: not sorted - SpewKeys is false.
+			[]reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
+			[]reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
+		},
+		// Invalid.
+		{
+			[]reflect.Value{embedB, embedA, embedC},
+			[]reflect.Value{embedB, embedA, embedC},
+		},
+	}
+	cs := spew.ConfigState{DisableMethods: true, SpewKeys: false}
+	helpTestSortValues(tests, &cs, t)
+}
+
+// TestSortValuesWithMethods ensures the sort functionality for relect.Value
+// based sorting works as intended when using string methods.
+func TestSortValuesWithMethods(t *testing.T) {
+	v := reflect.ValueOf
+
+	a := v("a")
+	b := v("b")
+	c := v("c")
+	tests := []sortTestCase{
+		// Ints.
+		{
+			[]reflect.Value{v(2), v(1), v(3)},
+			[]reflect.Value{v(1), v(2), v(3)},
+		},
+		// Strings.
+		{
+			[]reflect.Value{b, a, c},
+			[]reflect.Value{a, b, c},
+		},
+		// SortableStructs.
+		{
+			[]reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
+			[]reflect.Value{v(sortableStruct{1}), v(sortableStruct{2}), v(sortableStruct{3})},
+		},
+		// UnsortableStructs.
+		{
+			// Note: not sorted - SpewKeys is false.
+			[]reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
+			[]reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
+		},
+	}
+	cs := spew.ConfigState{DisableMethods: false, SpewKeys: false}
+	helpTestSortValues(tests, &cs, t)
+}
+
+// TestSortValuesWithSpew ensures the sort functionality for relect.Value
+// based sorting works as intended when using spew to stringify keys.
+func TestSortValuesWithSpew(t *testing.T) {
+	v := reflect.ValueOf
+
+	a := v("a")
+	b := v("b")
+	c := v("c")
+	tests := []sortTestCase{
+		// Ints.
+		{
+			[]reflect.Value{v(2), v(1), v(3)},
+			[]reflect.Value{v(1), v(2), v(3)},
+		},
+		// Strings.
+		{
+			[]reflect.Value{b, a, c},
+			[]reflect.Value{a, b, c},
+		},
+		// SortableStructs.
+		{
+			[]reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
+			[]reflect.Value{v(sortableStruct{1}), v(sortableStruct{2}), v(sortableStruct{3})},
+		},
+		// UnsortableStructs.
+		{
+			[]reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
+			[]reflect.Value{v(unsortableStruct{1}), v(unsortableStruct{2}), v(unsortableStruct{3})},
+		},
+	}
+	cs := spew.ConfigState{DisableMethods: true, SpewKeys: true}
+	helpTestSortValues(tests, &cs, t)
+}

+ 1042 - 0
vendor/github.com/davecgh/go-spew/spew/dump_test.go

@@ -0,0 +1,1042 @@
+/*
+ * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+Test Summary:
+NOTE: For each test, a nil pointer, a single pointer and double pointer to the
+base test element are also tested to ensure proper indirection across all types.
+
+- Max int8, int16, int32, int64, int
+- Max uint8, uint16, uint32, uint64, uint
+- Boolean true and false
+- Standard complex64 and complex128
+- Array containing standard ints
+- Array containing type with custom formatter on pointer receiver only
+- Array containing interfaces
+- Array containing bytes
+- Slice containing standard float32 values
+- Slice containing type with custom formatter on pointer receiver only
+- Slice containing interfaces
+- Slice containing bytes
+- Nil slice
+- Standard string
+- Nil interface
+- Sub-interface
+- Map with string keys and int vals
+- Map with custom formatter type on pointer receiver only keys and vals
+- Map with interface keys and values
+- Map with nil interface value
+- Struct with primitives
+- Struct that contains another struct
+- Struct that contains custom type with Stringer pointer interface via both
+  exported and unexported fields
+- Struct that contains embedded struct and field to same struct
+- Uintptr to 0 (null pointer)
+- Uintptr address of real variable
+- Unsafe.Pointer to 0 (null pointer)
+- Unsafe.Pointer to address of real variable
+- Nil channel
+- Standard int channel
+- Function with no params and no returns
+- Function with param and no returns
+- Function with multiple params and multiple returns
+- Struct that is circular through self referencing
+- Structs that are circular through cross referencing
+- Structs that are indirectly circular
+- Type that panics in its Stringer interface
+*/
+
+package spew_test
+
+import (
+	"bytes"
+	"fmt"
+	"testing"
+	"unsafe"
+
+	"github.com/davecgh/go-spew/spew"
+)
+
+// dumpTest is used to describe a test to be performed against the Dump method.
+type dumpTest struct {
+	in    interface{}
+	wants []string
+}
+
+// dumpTests houses all of the tests to be performed against the Dump method.
+var dumpTests = make([]dumpTest, 0)
+
+// addDumpTest is a helper method to append the passed input and desired result
+// to dumpTests
+func addDumpTest(in interface{}, wants ...string) {
+	test := dumpTest{in, wants}
+	dumpTests = append(dumpTests, test)
+}
+
+func addIntDumpTests() {
+	// Max int8.
+	v := int8(127)
+	nv := (*int8)(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vt := "int8"
+	vs := "127"
+	addDumpTest(v, "("+vt+") "+vs+"\n")
+	addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+	addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+	addDumpTest(nv, "(*"+vt+")(<nil>)\n")
+
+	// Max int16.
+	v2 := int16(32767)
+	nv2 := (*int16)(nil)
+	pv2 := &v2
+	v2Addr := fmt.Sprintf("%p", pv2)
+	pv2Addr := fmt.Sprintf("%p", &pv2)
+	v2t := "int16"
+	v2s := "32767"
+	addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+	addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
+	addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+	addDumpTest(nv2, "(*"+v2t+")(<nil>)\n")
+
+	// Max int32.
+	v3 := int32(2147483647)
+	nv3 := (*int32)(nil)
+	pv3 := &v3
+	v3Addr := fmt.Sprintf("%p", pv3)
+	pv3Addr := fmt.Sprintf("%p", &pv3)
+	v3t := "int32"
+	v3s := "2147483647"
+	addDumpTest(v3, "("+v3t+") "+v3s+"\n")
+	addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n")
+	addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n")
+	addDumpTest(nv3, "(*"+v3t+")(<nil>)\n")
+
+	// Max int64.
+	v4 := int64(9223372036854775807)
+	nv4 := (*int64)(nil)
+	pv4 := &v4
+	v4Addr := fmt.Sprintf("%p", pv4)
+	pv4Addr := fmt.Sprintf("%p", &pv4)
+	v4t := "int64"
+	v4s := "9223372036854775807"
+	addDumpTest(v4, "("+v4t+") "+v4s+"\n")
+	addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n")
+	addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n")
+	addDumpTest(nv4, "(*"+v4t+")(<nil>)\n")
+
+	// Max int.
+	v5 := int(2147483647)
+	nv5 := (*int)(nil)
+	pv5 := &v5
+	v5Addr := fmt.Sprintf("%p", pv5)
+	pv5Addr := fmt.Sprintf("%p", &pv5)
+	v5t := "int"
+	v5s := "2147483647"
+	addDumpTest(v5, "("+v5t+") "+v5s+"\n")
+	addDumpTest(pv5, "(*"+v5t+")("+v5Addr+")("+v5s+")\n")
+	addDumpTest(&pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")("+v5s+")\n")
+	addDumpTest(nv5, "(*"+v5t+")(<nil>)\n")
+}
+
+func addUintDumpTests() {
+	// Max uint8.
+	v := uint8(255)
+	nv := (*uint8)(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vt := "uint8"
+	vs := "255"
+	addDumpTest(v, "("+vt+") "+vs+"\n")
+	addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+	addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+	addDumpTest(nv, "(*"+vt+")(<nil>)\n")
+
+	// Max uint16.
+	v2 := uint16(65535)
+	nv2 := (*uint16)(nil)
+	pv2 := &v2
+	v2Addr := fmt.Sprintf("%p", pv2)
+	pv2Addr := fmt.Sprintf("%p", &pv2)
+	v2t := "uint16"
+	v2s := "65535"
+	addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+	addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
+	addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+	addDumpTest(nv2, "(*"+v2t+")(<nil>)\n")
+
+	// Max uint32.
+	v3 := uint32(4294967295)
+	nv3 := (*uint32)(nil)
+	pv3 := &v3
+	v3Addr := fmt.Sprintf("%p", pv3)
+	pv3Addr := fmt.Sprintf("%p", &pv3)
+	v3t := "uint32"
+	v3s := "4294967295"
+	addDumpTest(v3, "("+v3t+") "+v3s+"\n")
+	addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n")
+	addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n")
+	addDumpTest(nv3, "(*"+v3t+")(<nil>)\n")
+
+	// Max uint64.
+	v4 := uint64(18446744073709551615)
+	nv4 := (*uint64)(nil)
+	pv4 := &v4
+	v4Addr := fmt.Sprintf("%p", pv4)
+	pv4Addr := fmt.Sprintf("%p", &pv4)
+	v4t := "uint64"
+	v4s := "18446744073709551615"
+	addDumpTest(v4, "("+v4t+") "+v4s+"\n")
+	addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n")
+	addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n")
+	addDumpTest(nv4, "(*"+v4t+")(<nil>)\n")
+
+	// Max uint.
+	v5 := uint(4294967295)
+	nv5 := (*uint)(nil)
+	pv5 := &v5
+	v5Addr := fmt.Sprintf("%p", pv5)
+	pv5Addr := fmt.Sprintf("%p", &pv5)
+	v5t := "uint"
+	v5s := "4294967295"
+	addDumpTest(v5, "("+v5t+") "+v5s+"\n")
+	addDumpTest(pv5, "(*"+v5t+")("+v5Addr+")("+v5s+")\n")
+	addDumpTest(&pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")("+v5s+")\n")
+	addDumpTest(nv5, "(*"+v5t+")(<nil>)\n")
+}
+
+func addBoolDumpTests() {
+	// Boolean true.
+	v := bool(true)
+	nv := (*bool)(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vt := "bool"
+	vs := "true"
+	addDumpTest(v, "("+vt+") "+vs+"\n")
+	addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+	addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+	addDumpTest(nv, "(*"+vt+")(<nil>)\n")
+
+	// Boolean false.
+	v2 := bool(false)
+	pv2 := &v2
+	v2Addr := fmt.Sprintf("%p", pv2)
+	pv2Addr := fmt.Sprintf("%p", &pv2)
+	v2t := "bool"
+	v2s := "false"
+	addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+	addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
+	addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+}
+
+func addFloatDumpTests() {
+	// Standard float32.
+	v := float32(3.1415)
+	nv := (*float32)(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vt := "float32"
+	vs := "3.1415"
+	addDumpTest(v, "("+vt+") "+vs+"\n")
+	addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+	addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+	addDumpTest(nv, "(*"+vt+")(<nil>)\n")
+
+	// Standard float64.
+	v2 := float64(3.1415926)
+	nv2 := (*float64)(nil)
+	pv2 := &v2
+	v2Addr := fmt.Sprintf("%p", pv2)
+	pv2Addr := fmt.Sprintf("%p", &pv2)
+	v2t := "float64"
+	v2s := "3.1415926"
+	addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+	addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
+	addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+	addDumpTest(nv2, "(*"+v2t+")(<nil>)\n")
+}
+
+func addComplexDumpTests() {
+	// Standard complex64.
+	v := complex(float32(6), -2)
+	nv := (*complex64)(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vt := "complex64"
+	vs := "(6-2i)"
+	addDumpTest(v, "("+vt+") "+vs+"\n")
+	addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+	addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+	addDumpTest(nv, "(*"+vt+")(<nil>)\n")
+
+	// Standard complex128.
+	v2 := complex(float64(-6), 2)
+	nv2 := (*complex128)(nil)
+	pv2 := &v2
+	v2Addr := fmt.Sprintf("%p", pv2)
+	pv2Addr := fmt.Sprintf("%p", &pv2)
+	v2t := "complex128"
+	v2s := "(-6+2i)"
+	addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+	addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
+	addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+	addDumpTest(nv2, "(*"+v2t+")(<nil>)\n")
+}
+
+func addArrayDumpTests() {
+	// Array containing standard ints.
+	v := [3]int{1, 2, 3}
+	vLen := fmt.Sprintf("%d", len(v))
+	vCap := fmt.Sprintf("%d", cap(v))
+	nv := (*[3]int)(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vt := "int"
+	vs := "(len=" + vLen + " cap=" + vCap + ") {\n (" + vt + ") 1,\n (" +
+		vt + ") 2,\n (" + vt + ") 3\n}"
+	addDumpTest(v, "([3]"+vt+") "+vs+"\n")
+	addDumpTest(pv, "(*[3]"+vt+")("+vAddr+")("+vs+")\n")
+	addDumpTest(&pv, "(**[3]"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+	addDumpTest(nv, "(*[3]"+vt+")(<nil>)\n")
+
+	// Array containing type with custom formatter on pointer receiver only.
+	v2i0 := pstringer("1")
+	v2i1 := pstringer("2")
+	v2i2 := pstringer("3")
+	v2 := [3]pstringer{v2i0, v2i1, v2i2}
+	v2i0Len := fmt.Sprintf("%d", len(v2i0))
+	v2i1Len := fmt.Sprintf("%d", len(v2i1))
+	v2i2Len := fmt.Sprintf("%d", len(v2i2))
+	v2Len := fmt.Sprintf("%d", len(v2))
+	v2Cap := fmt.Sprintf("%d", cap(v2))
+	nv2 := (*[3]pstringer)(nil)
+	pv2 := &v2
+	v2Addr := fmt.Sprintf("%p", pv2)
+	pv2Addr := fmt.Sprintf("%p", &pv2)
+	v2t := "spew_test.pstringer"
+	v2sp := "(len=" + v2Len + " cap=" + v2Cap + ") {\n (" + v2t +
+		") (len=" + v2i0Len + ") stringer 1,\n (" + v2t +
+		") (len=" + v2i1Len + ") stringer 2,\n (" + v2t +
+		") (len=" + v2i2Len + ") " + "stringer 3\n}"
+	v2s := v2sp
+	if spew.UnsafeDisabled {
+		v2s = "(len=" + v2Len + " cap=" + v2Cap + ") {\n (" + v2t +
+			") (len=" + v2i0Len + ") \"1\",\n (" + v2t + ") (len=" +
+			v2i1Len + ") \"2\",\n (" + v2t + ") (len=" + v2i2Len +
+			") " + "\"3\"\n}"
+	}
+	addDumpTest(v2, "([3]"+v2t+") "+v2s+"\n")
+	addDumpTest(pv2, "(*[3]"+v2t+")("+v2Addr+")("+v2sp+")\n")
+	addDumpTest(&pv2, "(**[3]"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2sp+")\n")
+	addDumpTest(nv2, "(*[3]"+v2t+")(<nil>)\n")
+
+	// Array containing interfaces.
+	v3i0 := "one"
+	v3 := [3]interface{}{v3i0, int(2), uint(3)}
+	v3i0Len := fmt.Sprintf("%d", len(v3i0))
+	v3Len := fmt.Sprintf("%d", len(v3))
+	v3Cap := fmt.Sprintf("%d", cap(v3))
+	nv3 := (*[3]interface{})(nil)
+	pv3 := &v3
+	v3Addr := fmt.Sprintf("%p", pv3)
+	pv3Addr := fmt.Sprintf("%p", &pv3)
+	v3t := "[3]interface {}"
+	v3t2 := "string"
+	v3t3 := "int"
+	v3t4 := "uint"
+	v3s := "(len=" + v3Len + " cap=" + v3Cap + ") {\n (" + v3t2 + ") " +
+		"(len=" + v3i0Len + ") \"one\",\n (" + v3t3 + ") 2,\n (" +
+		v3t4 + ") 3\n}"
+	addDumpTest(v3, "("+v3t+") "+v3s+"\n")
+	addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n")
+	addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n")
+	addDumpTest(nv3, "(*"+v3t+")(<nil>)\n")
+
+	// Array containing bytes.
+	v4 := [34]byte{
+		0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+		0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+		0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+		0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
+		0x31, 0x32,
+	}
+	v4Len := fmt.Sprintf("%d", len(v4))
+	v4Cap := fmt.Sprintf("%d", cap(v4))
+	nv4 := (*[34]byte)(nil)
+	pv4 := &v4
+	v4Addr := fmt.Sprintf("%p", pv4)
+	pv4Addr := fmt.Sprintf("%p", &pv4)
+	v4t := "[34]uint8"
+	v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " +
+		"{\n 00000000  11 12 13 14 15 16 17 18  19 1a 1b 1c 1d 1e 1f 20" +
+		"  |............... |\n" +
+		" 00000010  21 22 23 24 25 26 27 28  29 2a 2b 2c 2d 2e 2f 30" +
+		"  |!\"#$%&'()*+,-./0|\n" +
+		" 00000020  31 32                                           " +
+		"  |12|\n}"
+	addDumpTest(v4, "("+v4t+") "+v4s+"\n")
+	addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n")
+	addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n")
+	addDumpTest(nv4, "(*"+v4t+")(<nil>)\n")
+}
+
+func addSliceDumpTests() {
+	// Slice containing standard float32 values.
+	v := []float32{3.14, 6.28, 12.56}
+	vLen := fmt.Sprintf("%d", len(v))
+	vCap := fmt.Sprintf("%d", cap(v))
+	nv := (*[]float32)(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vt := "float32"
+	vs := "(len=" + vLen + " cap=" + vCap + ") {\n (" + vt + ") 3.14,\n (" +
+		vt + ") 6.28,\n (" + vt + ") 12.56\n}"
+	addDumpTest(v, "([]"+vt+") "+vs+"\n")
+	addDumpTest(pv, "(*[]"+vt+")("+vAddr+")("+vs+")\n")
+	addDumpTest(&pv, "(**[]"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+	addDumpTest(nv, "(*[]"+vt+")(<nil>)\n")
+
+	// Slice containing type with custom formatter on pointer receiver only.
+	v2i0 := pstringer("1")
+	v2i1 := pstringer("2")
+	v2i2 := pstringer("3")
+	v2 := []pstringer{v2i0, v2i1, v2i2}
+	v2i0Len := fmt.Sprintf("%d", len(v2i0))
+	v2i1Len := fmt.Sprintf("%d", len(v2i1))
+	v2i2Len := fmt.Sprintf("%d", len(v2i2))
+	v2Len := fmt.Sprintf("%d", len(v2))
+	v2Cap := fmt.Sprintf("%d", cap(v2))
+	nv2 := (*[]pstringer)(nil)
+	pv2 := &v2
+	v2Addr := fmt.Sprintf("%p", pv2)
+	pv2Addr := fmt.Sprintf("%p", &pv2)
+	v2t := "spew_test.pstringer"
+	v2s := "(len=" + v2Len + " cap=" + v2Cap + ") {\n (" + v2t + ") (len=" +
+		v2i0Len + ") stringer 1,\n (" + v2t + ") (len=" + v2i1Len +
+		") stringer 2,\n (" + v2t + ") (len=" + v2i2Len + ") " +
+		"stringer 3\n}"
+	addDumpTest(v2, "([]"+v2t+") "+v2s+"\n")
+	addDumpTest(pv2, "(*[]"+v2t+")("+v2Addr+")("+v2s+")\n")
+	addDumpTest(&pv2, "(**[]"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+	addDumpTest(nv2, "(*[]"+v2t+")(<nil>)\n")
+
+	// Slice containing interfaces.
+	v3i0 := "one"
+	v3 := []interface{}{v3i0, int(2), uint(3), nil}
+	v3i0Len := fmt.Sprintf("%d", len(v3i0))
+	v3Len := fmt.Sprintf("%d", len(v3))
+	v3Cap := fmt.Sprintf("%d", cap(v3))
+	nv3 := (*[]interface{})(nil)
+	pv3 := &v3
+	v3Addr := fmt.Sprintf("%p", pv3)
+	pv3Addr := fmt.Sprintf("%p", &pv3)
+	v3t := "[]interface {}"
+	v3t2 := "string"
+	v3t3 := "int"
+	v3t4 := "uint"
+	v3t5 := "interface {}"
+	v3s := "(len=" + v3Len + " cap=" + v3Cap + ") {\n (" + v3t2 + ") " +
+		"(len=" + v3i0Len + ") \"one\",\n (" + v3t3 + ") 2,\n (" +
+		v3t4 + ") 3,\n (" + v3t5 + ") <nil>\n}"
+	addDumpTest(v3, "("+v3t+") "+v3s+"\n")
+	addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n")
+	addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n")
+	addDumpTest(nv3, "(*"+v3t+")(<nil>)\n")
+
+	// Slice containing bytes.
+	v4 := []byte{
+		0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+		0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+		0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+		0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
+		0x31, 0x32,
+	}
+	v4Len := fmt.Sprintf("%d", len(v4))
+	v4Cap := fmt.Sprintf("%d", cap(v4))
+	nv4 := (*[]byte)(nil)
+	pv4 := &v4
+	v4Addr := fmt.Sprintf("%p", pv4)
+	pv4Addr := fmt.Sprintf("%p", &pv4)
+	v4t := "[]uint8"
+	v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " +
+		"{\n 00000000  11 12 13 14 15 16 17 18  19 1a 1b 1c 1d 1e 1f 20" +
+		"  |............... |\n" +
+		" 00000010  21 22 23 24 25 26 27 28  29 2a 2b 2c 2d 2e 2f 30" +
+		"  |!\"#$%&'()*+,-./0|\n" +
+		" 00000020  31 32                                           " +
+		"  |12|\n}"
+	addDumpTest(v4, "("+v4t+") "+v4s+"\n")
+	addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n")
+	addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n")
+	addDumpTest(nv4, "(*"+v4t+")(<nil>)\n")
+
+	// Nil slice.
+	v5 := []int(nil)
+	nv5 := (*[]int)(nil)
+	pv5 := &v5
+	v5Addr := fmt.Sprintf("%p", pv5)
+	pv5Addr := fmt.Sprintf("%p", &pv5)
+	v5t := "[]int"
+	v5s := "<nil>"
+	addDumpTest(v5, "("+v5t+") "+v5s+"\n")
+	addDumpTest(pv5, "(*"+v5t+")("+v5Addr+")("+v5s+")\n")
+	addDumpTest(&pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")("+v5s+")\n")
+	addDumpTest(nv5, "(*"+v5t+")(<nil>)\n")
+}
+
+func addStringDumpTests() {
+	// Standard string.
+	v := "test"
+	vLen := fmt.Sprintf("%d", len(v))
+	nv := (*string)(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vt := "string"
+	vs := "(len=" + vLen + ") \"test\""
+	addDumpTest(v, "("+vt+") "+vs+"\n")
+	addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+	addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+	addDumpTest(nv, "(*"+vt+")(<nil>)\n")
+}
+
+func addInterfaceDumpTests() {
+	// Nil interface.
+	var v interface{}
+	nv := (*interface{})(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vt := "interface {}"
+	vs := "<nil>"
+	addDumpTest(v, "("+vt+") "+vs+"\n")
+	addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+	addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+	addDumpTest(nv, "(*"+vt+")(<nil>)\n")
+
+	// Sub-interface.
+	v2 := interface{}(uint16(65535))
+	pv2 := &v2
+	v2Addr := fmt.Sprintf("%p", pv2)
+	pv2Addr := fmt.Sprintf("%p", &pv2)
+	v2t := "uint16"
+	v2s := "65535"
+	addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+	addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
+	addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+}
+
+func addMapDumpTests() {
+	// Map with string keys and int vals.
+	k := "one"
+	kk := "two"
+	m := map[string]int{k: 1, kk: 2}
+	klen := fmt.Sprintf("%d", len(k)) // not kLen to shut golint up
+	kkLen := fmt.Sprintf("%d", len(kk))
+	mLen := fmt.Sprintf("%d", len(m))
+	nilMap := map[string]int(nil)
+	nm := (*map[string]int)(nil)
+	pm := &m
+	mAddr := fmt.Sprintf("%p", pm)
+	pmAddr := fmt.Sprintf("%p", &pm)
+	mt := "map[string]int"
+	mt1 := "string"
+	mt2 := "int"
+	ms := "(len=" + mLen + ") {\n (" + mt1 + ") (len=" + klen + ") " +
+		"\"one\": (" + mt2 + ") 1,\n (" + mt1 + ") (len=" + kkLen +
+		") \"two\": (" + mt2 + ") 2\n}"
+	ms2 := "(len=" + mLen + ") {\n (" + mt1 + ") (len=" + kkLen + ") " +
+		"\"two\": (" + mt2 + ") 2,\n (" + mt1 + ") (len=" + klen +
+		") \"one\": (" + mt2 + ") 1\n}"
+	addDumpTest(m, "("+mt+") "+ms+"\n", "("+mt+") "+ms2+"\n")
+	addDumpTest(pm, "(*"+mt+")("+mAddr+")("+ms+")\n",
+		"(*"+mt+")("+mAddr+")("+ms2+")\n")
+	addDumpTest(&pm, "(**"+mt+")("+pmAddr+"->"+mAddr+")("+ms+")\n",
+		"(**"+mt+")("+pmAddr+"->"+mAddr+")("+ms2+")\n")
+	addDumpTest(nm, "(*"+mt+")(<nil>)\n")
+	addDumpTest(nilMap, "("+mt+") <nil>\n")
+
+	// Map with custom formatter type on pointer receiver only keys and vals.
+	k2 := pstringer("one")
+	v2 := pstringer("1")
+	m2 := map[pstringer]pstringer{k2: v2}
+	k2Len := fmt.Sprintf("%d", len(k2))
+	v2Len := fmt.Sprintf("%d", len(v2))
+	m2Len := fmt.Sprintf("%d", len(m2))
+	nilMap2 := map[pstringer]pstringer(nil)
+	nm2 := (*map[pstringer]pstringer)(nil)
+	pm2 := &m2
+	m2Addr := fmt.Sprintf("%p", pm2)
+	pm2Addr := fmt.Sprintf("%p", &pm2)
+	m2t := "map[spew_test.pstringer]spew_test.pstringer"
+	m2t1 := "spew_test.pstringer"
+	m2t2 := "spew_test.pstringer"
+	m2s := "(len=" + m2Len + ") {\n (" + m2t1 + ") (len=" + k2Len + ") " +
+		"stringer one: (" + m2t2 + ") (len=" + v2Len + ") stringer 1\n}"
+	if spew.UnsafeDisabled {
+		m2s = "(len=" + m2Len + ") {\n (" + m2t1 + ") (len=" + k2Len +
+			") " + "\"one\": (" + m2t2 + ") (len=" + v2Len +
+			") \"1\"\n}"
+	}
+	addDumpTest(m2, "("+m2t+") "+m2s+"\n")
+	addDumpTest(pm2, "(*"+m2t+")("+m2Addr+")("+m2s+")\n")
+	addDumpTest(&pm2, "(**"+m2t+")("+pm2Addr+"->"+m2Addr+")("+m2s+")\n")
+	addDumpTest(nm2, "(*"+m2t+")(<nil>)\n")
+	addDumpTest(nilMap2, "("+m2t+") <nil>\n")
+
+	// Map with interface keys and values.
+	k3 := "one"
+	k3Len := fmt.Sprintf("%d", len(k3))
+	m3 := map[interface{}]interface{}{k3: 1}
+	m3Len := fmt.Sprintf("%d", len(m3))
+	nilMap3 := map[interface{}]interface{}(nil)
+	nm3 := (*map[interface{}]interface{})(nil)
+	pm3 := &m3
+	m3Addr := fmt.Sprintf("%p", pm3)
+	pm3Addr := fmt.Sprintf("%p", &pm3)
+	m3t := "map[interface {}]interface {}"
+	m3t1 := "string"
+	m3t2 := "int"
+	m3s := "(len=" + m3Len + ") {\n (" + m3t1 + ") (len=" + k3Len + ") " +
+		"\"one\": (" + m3t2 + ") 1\n}"
+	addDumpTest(m3, "("+m3t+") "+m3s+"\n")
+	addDumpTest(pm3, "(*"+m3t+")("+m3Addr+")("+m3s+")\n")
+	addDumpTest(&pm3, "(**"+m3t+")("+pm3Addr+"->"+m3Addr+")("+m3s+")\n")
+	addDumpTest(nm3, "(*"+m3t+")(<nil>)\n")
+	addDumpTest(nilMap3, "("+m3t+") <nil>\n")
+
+	// Map with nil interface value.
+	k4 := "nil"
+	k4Len := fmt.Sprintf("%d", len(k4))
+	m4 := map[string]interface{}{k4: nil}
+	m4Len := fmt.Sprintf("%d", len(m4))
+	nilMap4 := map[string]interface{}(nil)
+	nm4 := (*map[string]interface{})(nil)
+	pm4 := &m4
+	m4Addr := fmt.Sprintf("%p", pm4)
+	pm4Addr := fmt.Sprintf("%p", &pm4)
+	m4t := "map[string]interface {}"
+	m4t1 := "string"
+	m4t2 := "interface {}"
+	m4s := "(len=" + m4Len + ") {\n (" + m4t1 + ") (len=" + k4Len + ")" +
+		" \"nil\": (" + m4t2 + ") <nil>\n}"
+	addDumpTest(m4, "("+m4t+") "+m4s+"\n")
+	addDumpTest(pm4, "(*"+m4t+")("+m4Addr+")("+m4s+")\n")
+	addDumpTest(&pm4, "(**"+m4t+")("+pm4Addr+"->"+m4Addr+")("+m4s+")\n")
+	addDumpTest(nm4, "(*"+m4t+")(<nil>)\n")
+	addDumpTest(nilMap4, "("+m4t+") <nil>\n")
+}
+
+func addStructDumpTests() {
+	// Struct with primitives.
+	type s1 struct {
+		a int8
+		b uint8
+	}
+	v := s1{127, 255}
+	nv := (*s1)(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vt := "spew_test.s1"
+	vt2 := "int8"
+	vt3 := "uint8"
+	vs := "{\n a: (" + vt2 + ") 127,\n b: (" + vt3 + ") 255\n}"
+	addDumpTest(v, "("+vt+") "+vs+"\n")
+	addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+	addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+	addDumpTest(nv, "(*"+vt+")(<nil>)\n")
+
+	// Struct that contains another struct.
+	type s2 struct {
+		s1 s1
+		b  bool
+	}
+	v2 := s2{s1{127, 255}, true}
+	nv2 := (*s2)(nil)
+	pv2 := &v2
+	v2Addr := fmt.Sprintf("%p", pv2)
+	pv2Addr := fmt.Sprintf("%p", &pv2)
+	v2t := "spew_test.s2"
+	v2t2 := "spew_test.s1"
+	v2t3 := "int8"
+	v2t4 := "uint8"
+	v2t5 := "bool"
+	v2s := "{\n s1: (" + v2t2 + ") {\n  a: (" + v2t3 + ") 127,\n  b: (" +
+		v2t4 + ") 255\n },\n b: (" + v2t5 + ") true\n}"
+	addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+	addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
+	addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+	addDumpTest(nv2, "(*"+v2t+")(<nil>)\n")
+
+	// Struct that contains custom type with Stringer pointer interface via both
+	// exported and unexported fields.
+	type s3 struct {
+		s pstringer
+		S pstringer
+	}
+	v3 := s3{"test", "test2"}
+	nv3 := (*s3)(nil)
+	pv3 := &v3
+	v3Addr := fmt.Sprintf("%p", pv3)
+	pv3Addr := fmt.Sprintf("%p", &pv3)
+	v3t := "spew_test.s3"
+	v3t2 := "spew_test.pstringer"
+	v3s := "{\n s: (" + v3t2 + ") (len=4) stringer test,\n S: (" + v3t2 +
+		") (len=5) stringer test2\n}"
+	v3sp := v3s
+	if spew.UnsafeDisabled {
+		v3s = "{\n s: (" + v3t2 + ") (len=4) \"test\",\n S: (" +
+			v3t2 + ") (len=5) \"test2\"\n}"
+		v3sp = "{\n s: (" + v3t2 + ") (len=4) \"test\",\n S: (" +
+			v3t2 + ") (len=5) stringer test2\n}"
+	}
+	addDumpTest(v3, "("+v3t+") "+v3s+"\n")
+	addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3sp+")\n")
+	addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3sp+")\n")
+	addDumpTest(nv3, "(*"+v3t+")(<nil>)\n")
+
+	// Struct that contains embedded struct and field to same struct.
+	e := embed{"embedstr"}
+	eLen := fmt.Sprintf("%d", len("embedstr"))
+	v4 := embedwrap{embed: &e, e: &e}
+	nv4 := (*embedwrap)(nil)
+	pv4 := &v4
+	eAddr := fmt.Sprintf("%p", &e)
+	v4Addr := fmt.Sprintf("%p", pv4)
+	pv4Addr := fmt.Sprintf("%p", &pv4)
+	v4t := "spew_test.embedwrap"
+	v4t2 := "spew_test.embed"
+	v4t3 := "string"
+	v4s := "{\n embed: (*" + v4t2 + ")(" + eAddr + ")({\n  a: (" + v4t3 +
+		") (len=" + eLen + ") \"embedstr\"\n }),\n e: (*" + v4t2 +
+		")(" + eAddr + ")({\n  a: (" + v4t3 + ") (len=" + eLen + ")" +
+		" \"embedstr\"\n })\n}"
+	addDumpTest(v4, "("+v4t+") "+v4s+"\n")
+	addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n")
+	addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n")
+	addDumpTest(nv4, "(*"+v4t+")(<nil>)\n")
+}
+
+func addUintptrDumpTests() {
+	// Null pointer.
+	v := uintptr(0)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vt := "uintptr"
+	vs := "<nil>"
+	addDumpTest(v, "("+vt+") "+vs+"\n")
+	addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+	addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+
+	// Address of real variable.
+	i := 1
+	v2 := uintptr(unsafe.Pointer(&i))
+	nv2 := (*uintptr)(nil)
+	pv2 := &v2
+	v2Addr := fmt.Sprintf("%p", pv2)
+	pv2Addr := fmt.Sprintf("%p", &pv2)
+	v2t := "uintptr"
+	v2s := fmt.Sprintf("%p", &i)
+	addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+	addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
+	addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+	addDumpTest(nv2, "(*"+v2t+")(<nil>)\n")
+}
+
+func addUnsafePointerDumpTests() {
+	// Null pointer.
+	v := unsafe.Pointer(uintptr(0))
+	nv := (*unsafe.Pointer)(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vt := "unsafe.Pointer"
+	vs := "<nil>"
+	addDumpTest(v, "("+vt+") "+vs+"\n")
+	addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+	addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+	addDumpTest(nv, "(*"+vt+")(<nil>)\n")
+
+	// Address of real variable.
+	i := 1
+	v2 := unsafe.Pointer(&i)
+	pv2 := &v2
+	v2Addr := fmt.Sprintf("%p", pv2)
+	pv2Addr := fmt.Sprintf("%p", &pv2)
+	v2t := "unsafe.Pointer"
+	v2s := fmt.Sprintf("%p", &i)
+	addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+	addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
+	addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+	addDumpTest(nv, "(*"+vt+")(<nil>)\n")
+}
+
+func addChanDumpTests() {
+	// Nil channel.
+	var v chan int
+	pv := &v
+	nv := (*chan int)(nil)
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vt := "chan int"
+	vs := "<nil>"
+	addDumpTest(v, "("+vt+") "+vs+"\n")
+	addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+	addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+	addDumpTest(nv, "(*"+vt+")(<nil>)\n")
+
+	// Real channel.
+	v2 := make(chan int)
+	pv2 := &v2
+	v2Addr := fmt.Sprintf("%p", pv2)
+	pv2Addr := fmt.Sprintf("%p", &pv2)
+	v2t := "chan int"
+	v2s := fmt.Sprintf("%p", v2)
+	addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+	addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
+	addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+}
+
+func addFuncDumpTests() {
+	// Function with no params and no returns.
+	v := addIntDumpTests
+	nv := (*func())(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vt := "func()"
+	vs := fmt.Sprintf("%p", v)
+	addDumpTest(v, "("+vt+") "+vs+"\n")
+	addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+	addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+	addDumpTest(nv, "(*"+vt+")(<nil>)\n")
+
+	// Function with param and no returns.
+	v2 := TestDump
+	nv2 := (*func(*testing.T))(nil)
+	pv2 := &v2
+	v2Addr := fmt.Sprintf("%p", pv2)
+	pv2Addr := fmt.Sprintf("%p", &pv2)
+	v2t := "func(*testing.T)"
+	v2s := fmt.Sprintf("%p", v2)
+	addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+	addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
+	addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+	addDumpTest(nv2, "(*"+v2t+")(<nil>)\n")
+
+	// Function with multiple params and multiple returns.
+	var v3 = func(i int, s string) (b bool, err error) {
+		return true, nil
+	}
+	nv3 := (*func(int, string) (bool, error))(nil)
+	pv3 := &v3
+	v3Addr := fmt.Sprintf("%p", pv3)
+	pv3Addr := fmt.Sprintf("%p", &pv3)
+	v3t := "func(int, string) (bool, error)"
+	v3s := fmt.Sprintf("%p", v3)
+	addDumpTest(v3, "("+v3t+") "+v3s+"\n")
+	addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n")
+	addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n")
+	addDumpTest(nv3, "(*"+v3t+")(<nil>)\n")
+}
+
+func addCircularDumpTests() {
+	// Struct that is circular through self referencing.
+	type circular struct {
+		c *circular
+	}
+	v := circular{nil}
+	v.c = &v
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vt := "spew_test.circular"
+	vs := "{\n c: (*" + vt + ")(" + vAddr + ")({\n  c: (*" + vt + ")(" +
+		vAddr + ")(<already shown>)\n })\n}"
+	vs2 := "{\n c: (*" + vt + ")(" + vAddr + ")(<already shown>)\n}"
+	addDumpTest(v, "("+vt+") "+vs+"\n")
+	addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs2+")\n")
+	addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs2+")\n")
+
+	// Structs that are circular through cross referencing.
+	v2 := xref1{nil}
+	ts2 := xref2{&v2}
+	v2.ps2 = &ts2
+	pv2 := &v2
+	ts2Addr := fmt.Sprintf("%p", &ts2)
+	v2Addr := fmt.Sprintf("%p", pv2)
+	pv2Addr := fmt.Sprintf("%p", &pv2)
+	v2t := "spew_test.xref1"
+	v2t2 := "spew_test.xref2"
+	v2s := "{\n ps2: (*" + v2t2 + ")(" + ts2Addr + ")({\n  ps1: (*" + v2t +
+		")(" + v2Addr + ")({\n   ps2: (*" + v2t2 + ")(" + ts2Addr +
+		")(<already shown>)\n  })\n })\n}"
+	v2s2 := "{\n ps2: (*" + v2t2 + ")(" + ts2Addr + ")({\n  ps1: (*" + v2t +
+		")(" + v2Addr + ")(<already shown>)\n })\n}"
+	addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+	addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s2+")\n")
+	addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s2+")\n")
+
+	// Structs that are indirectly circular.
+	v3 := indirCir1{nil}
+	tic2 := indirCir2{nil}
+	tic3 := indirCir3{&v3}
+	tic2.ps3 = &tic3
+	v3.ps2 = &tic2
+	pv3 := &v3
+	tic2Addr := fmt.Sprintf("%p", &tic2)
+	tic3Addr := fmt.Sprintf("%p", &tic3)
+	v3Addr := fmt.Sprintf("%p", pv3)
+	pv3Addr := fmt.Sprintf("%p", &pv3)
+	v3t := "spew_test.indirCir1"
+	v3t2 := "spew_test.indirCir2"
+	v3t3 := "spew_test.indirCir3"
+	v3s := "{\n ps2: (*" + v3t2 + ")(" + tic2Addr + ")({\n  ps3: (*" + v3t3 +
+		")(" + tic3Addr + ")({\n   ps1: (*" + v3t + ")(" + v3Addr +
+		")({\n    ps2: (*" + v3t2 + ")(" + tic2Addr +
+		")(<already shown>)\n   })\n  })\n })\n}"
+	v3s2 := "{\n ps2: (*" + v3t2 + ")(" + tic2Addr + ")({\n  ps3: (*" + v3t3 +
+		")(" + tic3Addr + ")({\n   ps1: (*" + v3t + ")(" + v3Addr +
+		")(<already shown>)\n  })\n })\n}"
+	addDumpTest(v3, "("+v3t+") "+v3s+"\n")
+	addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s2+")\n")
+	addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s2+")\n")
+}
+
+func addPanicDumpTests() {
+	// Type that panics in its Stringer interface.
+	v := panicer(127)
+	nv := (*panicer)(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vt := "spew_test.panicer"
+	vs := "(PANIC=test panic)127"
+	addDumpTest(v, "("+vt+") "+vs+"\n")
+	addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+	addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+	addDumpTest(nv, "(*"+vt+")(<nil>)\n")
+}
+
+func addErrorDumpTests() {
+	// Type that has a custom Error interface.
+	v := customError(127)
+	nv := (*customError)(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vt := "spew_test.customError"
+	vs := "error: 127"
+	addDumpTest(v, "("+vt+") "+vs+"\n")
+	addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+	addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+	addDumpTest(nv, "(*"+vt+")(<nil>)\n")
+}
+
+// TestDump executes all of the tests described by dumpTests.
+func TestDump(t *testing.T) {
+	// Setup tests.
+	addIntDumpTests()
+	addUintDumpTests()
+	addBoolDumpTests()
+	addFloatDumpTests()
+	addComplexDumpTests()
+	addArrayDumpTests()
+	addSliceDumpTests()
+	addStringDumpTests()
+	addInterfaceDumpTests()
+	addMapDumpTests()
+	addStructDumpTests()
+	addUintptrDumpTests()
+	addUnsafePointerDumpTests()
+	addChanDumpTests()
+	addFuncDumpTests()
+	addCircularDumpTests()
+	addPanicDumpTests()
+	addErrorDumpTests()
+	addCgoDumpTests()
+
+	t.Logf("Running %d tests", len(dumpTests))
+	for i, test := range dumpTests {
+		buf := new(bytes.Buffer)
+		spew.Fdump(buf, test.in)
+		s := buf.String()
+		if testFailed(s, test.wants) {
+			t.Errorf("Dump #%d\n got: %s %s", i, s, stringizeWants(test.wants))
+			continue
+		}
+	}
+}
+
+func TestDumpSortedKeys(t *testing.T) {
+	cfg := spew.ConfigState{SortKeys: true}
+	s := cfg.Sdump(map[int]string{1: "1", 3: "3", 2: "2"})
+	expected := "(map[int]string) (len=3) {\n(int) 1: (string) (len=1) " +
+		"\"1\",\n(int) 2: (string) (len=1) \"2\",\n(int) 3: (string) " +
+		"(len=1) \"3\"\n" +
+		"}\n"
+	if s != expected {
+		t.Errorf("Sorted keys mismatch:\n  %v %v", s, expected)
+	}
+
+	s = cfg.Sdump(map[stringer]int{"1": 1, "3": 3, "2": 2})
+	expected = "(map[spew_test.stringer]int) (len=3) {\n" +
+		"(spew_test.stringer) (len=1) stringer 1: (int) 1,\n" +
+		"(spew_test.stringer) (len=1) stringer 2: (int) 2,\n" +
+		"(spew_test.stringer) (len=1) stringer 3: (int) 3\n" +
+		"}\n"
+	if s != expected {
+		t.Errorf("Sorted keys mismatch:\n  %v %v", s, expected)
+	}
+
+	s = cfg.Sdump(map[pstringer]int{pstringer("1"): 1, pstringer("3"): 3, pstringer("2"): 2})
+	expected = "(map[spew_test.pstringer]int) (len=3) {\n" +
+		"(spew_test.pstringer) (len=1) stringer 1: (int) 1,\n" +
+		"(spew_test.pstringer) (len=1) stringer 2: (int) 2,\n" +
+		"(spew_test.pstringer) (len=1) stringer 3: (int) 3\n" +
+		"}\n"
+	if spew.UnsafeDisabled {
+		expected = "(map[spew_test.pstringer]int) (len=3) {\n" +
+			"(spew_test.pstringer) (len=1) \"1\": (int) 1,\n" +
+			"(spew_test.pstringer) (len=1) \"2\": (int) 2,\n" +
+			"(spew_test.pstringer) (len=1) \"3\": (int) 3\n" +
+			"}\n"
+	}
+	if s != expected {
+		t.Errorf("Sorted keys mismatch:\n  %v %v", s, expected)
+	}
+
+	s = cfg.Sdump(map[customError]int{customError(1): 1, customError(3): 3, customError(2): 2})
+	expected = "(map[spew_test.customError]int) (len=3) {\n" +
+		"(spew_test.customError) error: 1: (int) 1,\n" +
+		"(spew_test.customError) error: 2: (int) 2,\n" +
+		"(spew_test.customError) error: 3: (int) 3\n" +
+		"}\n"
+	if s != expected {
+		t.Errorf("Sorted keys mismatch:\n  %v %v", s, expected)
+	}
+
+}

+ 99 - 0
vendor/github.com/davecgh/go-spew/spew/dumpcgo_test.go

@@ -0,0 +1,99 @@
+// Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
+//
+// Permission to use, copy, modify, and distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+// NOTE: Due to the following build constraints, this file will only be compiled
+// when both cgo is supported and "-tags testcgo" is added to the go test
+// command line.  This means the cgo tests are only added (and hence run) when
+// specifially requested.  This configuration is used because spew itself
+// does not require cgo to run even though it does handle certain cgo types
+// specially.  Rather than forcing all clients to require cgo and an external
+// C compiler just to run the tests, this scheme makes them optional.
+// +build cgo,testcgo
+
+package spew_test
+
+import (
+	"fmt"
+
+	"github.com/davecgh/go-spew/spew/testdata"
+)
+
+func addCgoDumpTests() {
+	// C char pointer.
+	v := testdata.GetCgoCharPointer()
+	nv := testdata.GetCgoNullCharPointer()
+	pv := &v
+	vcAddr := fmt.Sprintf("%p", v)
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vt := "*testdata._Ctype_char"
+	vs := "116"
+	addDumpTest(v, "("+vt+")("+vcAddr+")("+vs+")\n")
+	addDumpTest(pv, "(*"+vt+")("+vAddr+"->"+vcAddr+")("+vs+")\n")
+	addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+"->"+vcAddr+")("+vs+")\n")
+	addDumpTest(nv, "("+vt+")(<nil>)\n")
+
+	// C char array.
+	v2, v2l, v2c := testdata.GetCgoCharArray()
+	v2Len := fmt.Sprintf("%d", v2l)
+	v2Cap := fmt.Sprintf("%d", v2c)
+	v2t := "[6]testdata._Ctype_char"
+	v2s := "(len=" + v2Len + " cap=" + v2Cap + ") " +
+		"{\n 00000000  74 65 73 74 32 00                               " +
+		"  |test2.|\n}"
+	addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+
+	// C unsigned char array.
+	v3, v3l, v3c := testdata.GetCgoUnsignedCharArray()
+	v3Len := fmt.Sprintf("%d", v3l)
+	v3Cap := fmt.Sprintf("%d", v3c)
+	v3t := "[6]testdata._Ctype_unsignedchar"
+	v3t2 := "[6]testdata._Ctype_uchar"
+	v3s := "(len=" + v3Len + " cap=" + v3Cap + ") " +
+		"{\n 00000000  74 65 73 74 33 00                               " +
+		"  |test3.|\n}"
+	addDumpTest(v3, "("+v3t+") "+v3s+"\n", "("+v3t2+") "+v3s+"\n")
+
+	// C signed char array.
+	v4, v4l, v4c := testdata.GetCgoSignedCharArray()
+	v4Len := fmt.Sprintf("%d", v4l)
+	v4Cap := fmt.Sprintf("%d", v4c)
+	v4t := "[6]testdata._Ctype_schar"
+	v4t2 := "testdata._Ctype_schar"
+	v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " +
+		"{\n (" + v4t2 + ") 116,\n (" + v4t2 + ") 101,\n (" + v4t2 +
+		") 115,\n (" + v4t2 + ") 116,\n (" + v4t2 + ") 52,\n (" + v4t2 +
+		") 0\n}"
+	addDumpTest(v4, "("+v4t+") "+v4s+"\n")
+
+	// C uint8_t array.
+	v5, v5l, v5c := testdata.GetCgoUint8tArray()
+	v5Len := fmt.Sprintf("%d", v5l)
+	v5Cap := fmt.Sprintf("%d", v5c)
+	v5t := "[6]testdata._Ctype_uint8_t"
+	v5s := "(len=" + v5Len + " cap=" + v5Cap + ") " +
+		"{\n 00000000  74 65 73 74 35 00                               " +
+		"  |test5.|\n}"
+	addDumpTest(v5, "("+v5t+") "+v5s+"\n")
+
+	// C typedefed unsigned char array.
+	v6, v6l, v6c := testdata.GetCgoTypdefedUnsignedCharArray()
+	v6Len := fmt.Sprintf("%d", v6l)
+	v6Cap := fmt.Sprintf("%d", v6c)
+	v6t := "[6]testdata._Ctype_custom_uchar_t"
+	v6s := "(len=" + v6Len + " cap=" + v6Cap + ") " +
+		"{\n 00000000  74 65 73 74 36 00                               " +
+		"  |test6.|\n}"
+	addDumpTest(v6, "("+v6t+") "+v6s+"\n")
+}

+ 26 - 0
vendor/github.com/davecgh/go-spew/spew/dumpnocgo_test.go

@@ -0,0 +1,26 @@
+// Copyright (c) 2013 Dave Collins <dave@davec.name>
+//
+// Permission to use, copy, modify, and distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+// NOTE: Due to the following build constraints, this file will only be compiled
+// when either cgo is not supported or "-tags testcgo" is not added to the go
+// test command line.  This file intentionally does not setup any cgo tests in
+// this scenario.
+// +build !cgo !testcgo
+
+package spew_test
+
+func addCgoDumpTests() {
+	// Don't add any tests for cgo since this file is only compiled when
+	// there should not be any cgo tests.
+}

+ 226 - 0
vendor/github.com/davecgh/go-spew/spew/example_test.go

@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+package spew_test
+
+import (
+	"fmt"
+
+	"github.com/davecgh/go-spew/spew"
+)
+
+type Flag int
+
+const (
+	flagOne Flag = iota
+	flagTwo
+)
+
+var flagStrings = map[Flag]string{
+	flagOne: "flagOne",
+	flagTwo: "flagTwo",
+}
+
+func (f Flag) String() string {
+	if s, ok := flagStrings[f]; ok {
+		return s
+	}
+	return fmt.Sprintf("Unknown flag (%d)", int(f))
+}
+
+type Bar struct {
+	data uintptr
+}
+
+type Foo struct {
+	unexportedField Bar
+	ExportedField   map[interface{}]interface{}
+}
+
+// This example demonstrates how to use Dump to dump variables to stdout.
+func ExampleDump() {
+	// The following package level declarations are assumed for this example:
+	/*
+		type Flag int
+
+		const (
+			flagOne Flag = iota
+			flagTwo
+		)
+
+		var flagStrings = map[Flag]string{
+			flagOne: "flagOne",
+			flagTwo: "flagTwo",
+		}
+
+		func (f Flag) String() string {
+			if s, ok := flagStrings[f]; ok {
+				return s
+			}
+			return fmt.Sprintf("Unknown flag (%d)", int(f))
+		}
+
+		type Bar struct {
+			data uintptr
+		}
+
+		type Foo struct {
+			unexportedField Bar
+			ExportedField   map[interface{}]interface{}
+		}
+	*/
+
+	// Setup some sample data structures for the example.
+	bar := Bar{uintptr(0)}
+	s1 := Foo{bar, map[interface{}]interface{}{"one": true}}
+	f := Flag(5)
+	b := []byte{
+		0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+		0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+		0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+		0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
+		0x31, 0x32,
+	}
+
+	// Dump!
+	spew.Dump(s1, f, b)
+
+	// Output:
+	// (spew_test.Foo) {
+	//  unexportedField: (spew_test.Bar) {
+	//   data: (uintptr) <nil>
+	//  },
+	//  ExportedField: (map[interface {}]interface {}) (len=1) {
+	//   (string) (len=3) "one": (bool) true
+	//  }
+	// }
+	// (spew_test.Flag) Unknown flag (5)
+	// ([]uint8) (len=34 cap=34) {
+	//  00000000  11 12 13 14 15 16 17 18  19 1a 1b 1c 1d 1e 1f 20  |............... |
+	//  00000010  21 22 23 24 25 26 27 28  29 2a 2b 2c 2d 2e 2f 30  |!"#$%&'()*+,-./0|
+	//  00000020  31 32                                             |12|
+	// }
+	//
+}
+
+// This example demonstrates how to use Printf to display a variable with a
+// format string and inline formatting.
+func ExamplePrintf() {
+	// Create a double pointer to a uint 8.
+	ui8 := uint8(5)
+	pui8 := &ui8
+	ppui8 := &pui8
+
+	// Create a circular data type.
+	type circular struct {
+		ui8 uint8
+		c   *circular
+	}
+	c := circular{ui8: 1}
+	c.c = &c
+
+	// Print!
+	spew.Printf("ppui8: %v\n", ppui8)
+	spew.Printf("circular: %v\n", c)
+
+	// Output:
+	// ppui8: <**>5
+	// circular: {1 <*>{1 <*><shown>}}
+}
+
+// This example demonstrates how to use a ConfigState.
+func ExampleConfigState() {
+	// Modify the indent level of the ConfigState only.  The global
+	// configuration is not modified.
+	scs := spew.ConfigState{Indent: "\t"}
+
+	// Output using the ConfigState instance.
+	v := map[string]int{"one": 1}
+	scs.Printf("v: %v\n", v)
+	scs.Dump(v)
+
+	// Output:
+	// v: map[one:1]
+	// (map[string]int) (len=1) {
+	// 	(string) (len=3) "one": (int) 1
+	// }
+}
+
+// This example demonstrates how to use ConfigState.Dump to dump variables to
+// stdout
+func ExampleConfigState_Dump() {
+	// See the top-level Dump example for details on the types used in this
+	// example.
+
+	// Create two ConfigState instances with different indentation.
+	scs := spew.ConfigState{Indent: "\t"}
+	scs2 := spew.ConfigState{Indent: " "}
+
+	// Setup some sample data structures for the example.
+	bar := Bar{uintptr(0)}
+	s1 := Foo{bar, map[interface{}]interface{}{"one": true}}
+
+	// Dump using the ConfigState instances.
+	scs.Dump(s1)
+	scs2.Dump(s1)
+
+	// Output:
+	// (spew_test.Foo) {
+	// 	unexportedField: (spew_test.Bar) {
+	// 		data: (uintptr) <nil>
+	// 	},
+	// 	ExportedField: (map[interface {}]interface {}) (len=1) {
+	//		(string) (len=3) "one": (bool) true
+	// 	}
+	// }
+	// (spew_test.Foo) {
+	//  unexportedField: (spew_test.Bar) {
+	//   data: (uintptr) <nil>
+	//  },
+	//  ExportedField: (map[interface {}]interface {}) (len=1) {
+	//   (string) (len=3) "one": (bool) true
+	//  }
+	// }
+	//
+}
+
+// This example demonstrates how to use ConfigState.Printf to display a variable
+// with a format string and inline formatting.
+func ExampleConfigState_Printf() {
+	// See the top-level Dump example for details on the types used in this
+	// example.
+
+	// Create two ConfigState instances and modify the method handling of the
+	// first ConfigState only.
+	scs := spew.NewDefaultConfig()
+	scs2 := spew.NewDefaultConfig()
+	scs.DisableMethods = true
+
+	// Alternatively
+	// scs := spew.ConfigState{Indent: " ", DisableMethods: true}
+	// scs2 := spew.ConfigState{Indent: " "}
+
+	// This is of type Flag which implements a Stringer and has raw value 1.
+	f := flagTwo
+
+	// Dump using the ConfigState instances.
+	scs.Printf("f: %v\n", f)
+	scs2.Printf("f: %v\n", f)
+
+	// Output:
+	// f: 1
+	// f: flagTwo
+}

+ 1558 - 0
vendor/github.com/davecgh/go-spew/spew/format_test.go

@@ -0,0 +1,1558 @@
+/*
+ * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+Test Summary:
+NOTE: For each test, a nil pointer, a single pointer and double pointer to the
+base test element are also tested to ensure proper indirection across all types.
+
+- Max int8, int16, int32, int64, int
+- Max uint8, uint16, uint32, uint64, uint
+- Boolean true and false
+- Standard complex64 and complex128
+- Array containing standard ints
+- Array containing type with custom formatter on pointer receiver only
+- Array containing interfaces
+- Slice containing standard float32 values
+- Slice containing type with custom formatter on pointer receiver only
+- Slice containing interfaces
+- Nil slice
+- Standard string
+- Nil interface
+- Sub-interface
+- Map with string keys and int vals
+- Map with custom formatter type on pointer receiver only keys and vals
+- Map with interface keys and values
+- Map with nil interface value
+- Struct with primitives
+- Struct that contains another struct
+- Struct that contains custom type with Stringer pointer interface via both
+  exported and unexported fields
+- Struct that contains embedded struct and field to same struct
+- Uintptr to 0 (null pointer)
+- Uintptr address of real variable
+- Unsafe.Pointer to 0 (null pointer)
+- Unsafe.Pointer to address of real variable
+- Nil channel
+- Standard int channel
+- Function with no params and no returns
+- Function with param and no returns
+- Function with multiple params and multiple returns
+- Struct that is circular through self referencing
+- Structs that are circular through cross referencing
+- Structs that are indirectly circular
+- Type that panics in its Stringer interface
+- Type that has a custom Error interface
+- %x passthrough with uint
+- %#x passthrough with uint
+- %f passthrough with precision
+- %f passthrough with width and precision
+- %d passthrough with width
+- %q passthrough with string
+*/
+
+package spew_test
+
+import (
+	"bytes"
+	"fmt"
+	"testing"
+	"unsafe"
+
+	"github.com/davecgh/go-spew/spew"
+)
+
+// formatterTest is used to describe a test to be performed against NewFormatter.
+type formatterTest struct {
+	format string
+	in     interface{}
+	wants  []string
+}
+
+// formatterTests houses all of the tests to be performed against NewFormatter.
+var formatterTests = make([]formatterTest, 0)
+
+// addFormatterTest is a helper method to append the passed input and desired
+// result to formatterTests.
+func addFormatterTest(format string, in interface{}, wants ...string) {
+	test := formatterTest{format, in, wants}
+	formatterTests = append(formatterTests, test)
+}
+
+func addIntFormatterTests() {
+	// Max int8.
+	v := int8(127)
+	nv := (*int8)(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vt := "int8"
+	vs := "127"
+	addFormatterTest("%v", v, vs)
+	addFormatterTest("%v", pv, "<*>"+vs)
+	addFormatterTest("%v", &pv, "<**>"+vs)
+	addFormatterTest("%v", nv, "<nil>")
+	addFormatterTest("%+v", v, vs)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%#v", v, "("+vt+")"+vs)
+	addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+	addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+	addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+	addFormatterTest("%#+v", v, "("+vt+")"+vs)
+	addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+	addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+
+	// Max int16.
+	v2 := int16(32767)
+	nv2 := (*int16)(nil)
+	pv2 := &v2
+	v2Addr := fmt.Sprintf("%p", pv2)
+	pv2Addr := fmt.Sprintf("%p", &pv2)
+	v2t := "int16"
+	v2s := "32767"
+	addFormatterTest("%v", v2, v2s)
+	addFormatterTest("%v", pv2, "<*>"+v2s)
+	addFormatterTest("%v", &pv2, "<**>"+v2s)
+	addFormatterTest("%v", nv2, "<nil>")
+	addFormatterTest("%+v", v2, v2s)
+	addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+	addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+	addFormatterTest("%+v", nv2, "<nil>")
+	addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+	addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+	addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+	addFormatterTest("%#v", nv2, "(*"+v2t+")"+"<nil>")
+	addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+	addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+	addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+	addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"<nil>")
+
+	// Max int32.
+	v3 := int32(2147483647)
+	nv3 := (*int32)(nil)
+	pv3 := &v3
+	v3Addr := fmt.Sprintf("%p", pv3)
+	pv3Addr := fmt.Sprintf("%p", &pv3)
+	v3t := "int32"
+	v3s := "2147483647"
+	addFormatterTest("%v", v3, v3s)
+	addFormatterTest("%v", pv3, "<*>"+v3s)
+	addFormatterTest("%v", &pv3, "<**>"+v3s)
+	addFormatterTest("%v", nv3, "<nil>")
+	addFormatterTest("%+v", v3, v3s)
+	addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s)
+	addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s)
+	addFormatterTest("%+v", nv3, "<nil>")
+	addFormatterTest("%#v", v3, "("+v3t+")"+v3s)
+	addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s)
+	addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s)
+	addFormatterTest("%#v", nv3, "(*"+v3t+")"+"<nil>")
+	addFormatterTest("%#+v", v3, "("+v3t+")"+v3s)
+	addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s)
+	addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s)
+	addFormatterTest("%#v", nv3, "(*"+v3t+")"+"<nil>")
+
+	// Max int64.
+	v4 := int64(9223372036854775807)
+	nv4 := (*int64)(nil)
+	pv4 := &v4
+	v4Addr := fmt.Sprintf("%p", pv4)
+	pv4Addr := fmt.Sprintf("%p", &pv4)
+	v4t := "int64"
+	v4s := "9223372036854775807"
+	addFormatterTest("%v", v4, v4s)
+	addFormatterTest("%v", pv4, "<*>"+v4s)
+	addFormatterTest("%v", &pv4, "<**>"+v4s)
+	addFormatterTest("%v", nv4, "<nil>")
+	addFormatterTest("%+v", v4, v4s)
+	addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s)
+	addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s)
+	addFormatterTest("%+v", nv4, "<nil>")
+	addFormatterTest("%#v", v4, "("+v4t+")"+v4s)
+	addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s)
+	addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s)
+	addFormatterTest("%#v", nv4, "(*"+v4t+")"+"<nil>")
+	addFormatterTest("%#+v", v4, "("+v4t+")"+v4s)
+	addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s)
+	addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s)
+	addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"<nil>")
+
+	// Max int.
+	v5 := int(2147483647)
+	nv5 := (*int)(nil)
+	pv5 := &v5
+	v5Addr := fmt.Sprintf("%p", pv5)
+	pv5Addr := fmt.Sprintf("%p", &pv5)
+	v5t := "int"
+	v5s := "2147483647"
+	addFormatterTest("%v", v5, v5s)
+	addFormatterTest("%v", pv5, "<*>"+v5s)
+	addFormatterTest("%v", &pv5, "<**>"+v5s)
+	addFormatterTest("%v", nv5, "<nil>")
+	addFormatterTest("%+v", v5, v5s)
+	addFormatterTest("%+v", pv5, "<*>("+v5Addr+")"+v5s)
+	addFormatterTest("%+v", &pv5, "<**>("+pv5Addr+"->"+v5Addr+")"+v5s)
+	addFormatterTest("%+v", nv5, "<nil>")
+	addFormatterTest("%#v", v5, "("+v5t+")"+v5s)
+	addFormatterTest("%#v", pv5, "(*"+v5t+")"+v5s)
+	addFormatterTest("%#v", &pv5, "(**"+v5t+")"+v5s)
+	addFormatterTest("%#v", nv5, "(*"+v5t+")"+"<nil>")
+	addFormatterTest("%#+v", v5, "("+v5t+")"+v5s)
+	addFormatterTest("%#+v", pv5, "(*"+v5t+")("+v5Addr+")"+v5s)
+	addFormatterTest("%#+v", &pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")"+v5s)
+	addFormatterTest("%#+v", nv5, "(*"+v5t+")"+"<nil>")
+}
+
+func addUintFormatterTests() {
+	// Max uint8.
+	v := uint8(255)
+	nv := (*uint8)(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vt := "uint8"
+	vs := "255"
+	addFormatterTest("%v", v, vs)
+	addFormatterTest("%v", pv, "<*>"+vs)
+	addFormatterTest("%v", &pv, "<**>"+vs)
+	addFormatterTest("%v", nv, "<nil>")
+	addFormatterTest("%+v", v, vs)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%#v", v, "("+vt+")"+vs)
+	addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+	addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+	addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+	addFormatterTest("%#+v", v, "("+vt+")"+vs)
+	addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+	addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+
+	// Max uint16.
+	v2 := uint16(65535)
+	nv2 := (*uint16)(nil)
+	pv2 := &v2
+	v2Addr := fmt.Sprintf("%p", pv2)
+	pv2Addr := fmt.Sprintf("%p", &pv2)
+	v2t := "uint16"
+	v2s := "65535"
+	addFormatterTest("%v", v2, v2s)
+	addFormatterTest("%v", pv2, "<*>"+v2s)
+	addFormatterTest("%v", &pv2, "<**>"+v2s)
+	addFormatterTest("%v", nv2, "<nil>")
+	addFormatterTest("%+v", v2, v2s)
+	addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+	addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+	addFormatterTest("%+v", nv2, "<nil>")
+	addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+	addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+	addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+	addFormatterTest("%#v", nv2, "(*"+v2t+")"+"<nil>")
+	addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+	addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+	addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+	addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"<nil>")
+
+	// Max uint32.
+	v3 := uint32(4294967295)
+	nv3 := (*uint32)(nil)
+	pv3 := &v3
+	v3Addr := fmt.Sprintf("%p", pv3)
+	pv3Addr := fmt.Sprintf("%p", &pv3)
+	v3t := "uint32"
+	v3s := "4294967295"
+	addFormatterTest("%v", v3, v3s)
+	addFormatterTest("%v", pv3, "<*>"+v3s)
+	addFormatterTest("%v", &pv3, "<**>"+v3s)
+	addFormatterTest("%v", nv3, "<nil>")
+	addFormatterTest("%+v", v3, v3s)
+	addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s)
+	addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s)
+	addFormatterTest("%+v", nv3, "<nil>")
+	addFormatterTest("%#v", v3, "("+v3t+")"+v3s)
+	addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s)
+	addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s)
+	addFormatterTest("%#v", nv3, "(*"+v3t+")"+"<nil>")
+	addFormatterTest("%#+v", v3, "("+v3t+")"+v3s)
+	addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s)
+	addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s)
+	addFormatterTest("%#v", nv3, "(*"+v3t+")"+"<nil>")
+
+	// Max uint64.
+	v4 := uint64(18446744073709551615)
+	nv4 := (*uint64)(nil)
+	pv4 := &v4
+	v4Addr := fmt.Sprintf("%p", pv4)
+	pv4Addr := fmt.Sprintf("%p", &pv4)
+	v4t := "uint64"
+	v4s := "18446744073709551615"
+	addFormatterTest("%v", v4, v4s)
+	addFormatterTest("%v", pv4, "<*>"+v4s)
+	addFormatterTest("%v", &pv4, "<**>"+v4s)
+	addFormatterTest("%v", nv4, "<nil>")
+	addFormatterTest("%+v", v4, v4s)
+	addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s)
+	addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s)
+	addFormatterTest("%+v", nv4, "<nil>")
+	addFormatterTest("%#v", v4, "("+v4t+")"+v4s)
+	addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s)
+	addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s)
+	addFormatterTest("%#v", nv4, "(*"+v4t+")"+"<nil>")
+	addFormatterTest("%#+v", v4, "("+v4t+")"+v4s)
+	addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s)
+	addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s)
+	addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"<nil>")
+
+	// Max uint.
+	v5 := uint(4294967295)
+	nv5 := (*uint)(nil)
+	pv5 := &v5
+	v5Addr := fmt.Sprintf("%p", pv5)
+	pv5Addr := fmt.Sprintf("%p", &pv5)
+	v5t := "uint"
+	v5s := "4294967295"
+	addFormatterTest("%v", v5, v5s)
+	addFormatterTest("%v", pv5, "<*>"+v5s)
+	addFormatterTest("%v", &pv5, "<**>"+v5s)
+	addFormatterTest("%v", nv5, "<nil>")
+	addFormatterTest("%+v", v5, v5s)
+	addFormatterTest("%+v", pv5, "<*>("+v5Addr+")"+v5s)
+	addFormatterTest("%+v", &pv5, "<**>("+pv5Addr+"->"+v5Addr+")"+v5s)
+	addFormatterTest("%+v", nv5, "<nil>")
+	addFormatterTest("%#v", v5, "("+v5t+")"+v5s)
+	addFormatterTest("%#v", pv5, "(*"+v5t+")"+v5s)
+	addFormatterTest("%#v", &pv5, "(**"+v5t+")"+v5s)
+	addFormatterTest("%#v", nv5, "(*"+v5t+")"+"<nil>")
+	addFormatterTest("%#+v", v5, "("+v5t+")"+v5s)
+	addFormatterTest("%#+v", pv5, "(*"+v5t+")("+v5Addr+")"+v5s)
+	addFormatterTest("%#+v", &pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")"+v5s)
+	addFormatterTest("%#v", nv5, "(*"+v5t+")"+"<nil>")
+}
+
+func addBoolFormatterTests() {
+	// Boolean true.
+	v := bool(true)
+	nv := (*bool)(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vt := "bool"
+	vs := "true"
+	addFormatterTest("%v", v, vs)
+	addFormatterTest("%v", pv, "<*>"+vs)
+	addFormatterTest("%v", &pv, "<**>"+vs)
+	addFormatterTest("%v", nv, "<nil>")
+	addFormatterTest("%+v", v, vs)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%#v", v, "("+vt+")"+vs)
+	addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+	addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+	addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+	addFormatterTest("%#+v", v, "("+vt+")"+vs)
+	addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+	addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+
+	// Boolean false.
+	v2 := bool(false)
+	pv2 := &v2
+	v2Addr := fmt.Sprintf("%p", pv2)
+	pv2Addr := fmt.Sprintf("%p", &pv2)
+	v2t := "bool"
+	v2s := "false"
+	addFormatterTest("%v", v2, v2s)
+	addFormatterTest("%v", pv2, "<*>"+v2s)
+	addFormatterTest("%v", &pv2, "<**>"+v2s)
+	addFormatterTest("%+v", v2, v2s)
+	addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+	addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+	addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+	addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+	addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+	addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+	addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+	addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+}
+
+func addFloatFormatterTests() {
+	// Standard float32.
+	v := float32(3.1415)
+	nv := (*float32)(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vt := "float32"
+	vs := "3.1415"
+	addFormatterTest("%v", v, vs)
+	addFormatterTest("%v", pv, "<*>"+vs)
+	addFormatterTest("%v", &pv, "<**>"+vs)
+	addFormatterTest("%v", nv, "<nil>")
+	addFormatterTest("%+v", v, vs)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%#v", v, "("+vt+")"+vs)
+	addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+	addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+	addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+	addFormatterTest("%#+v", v, "("+vt+")"+vs)
+	addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+	addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+
+	// Standard float64.
+	v2 := float64(3.1415926)
+	nv2 := (*float64)(nil)
+	pv2 := &v2
+	v2Addr := fmt.Sprintf("%p", pv2)
+	pv2Addr := fmt.Sprintf("%p", &pv2)
+	v2t := "float64"
+	v2s := "3.1415926"
+	addFormatterTest("%v", v2, v2s)
+	addFormatterTest("%v", pv2, "<*>"+v2s)
+	addFormatterTest("%v", &pv2, "<**>"+v2s)
+	addFormatterTest("%+v", nv2, "<nil>")
+	addFormatterTest("%+v", v2, v2s)
+	addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+	addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+	addFormatterTest("%+v", nv2, "<nil>")
+	addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+	addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+	addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+	addFormatterTest("%#v", nv2, "(*"+v2t+")"+"<nil>")
+	addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+	addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+	addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+	addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"<nil>")
+}
+
+func addComplexFormatterTests() {
+	// Standard complex64.
+	v := complex(float32(6), -2)
+	nv := (*complex64)(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vt := "complex64"
+	vs := "(6-2i)"
+	addFormatterTest("%v", v, vs)
+	addFormatterTest("%v", pv, "<*>"+vs)
+	addFormatterTest("%v", &pv, "<**>"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%+v", v, vs)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%#v", v, "("+vt+")"+vs)
+	addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+	addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+	addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+	addFormatterTest("%#+v", v, "("+vt+")"+vs)
+	addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+	addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+
+	// Standard complex128.
+	v2 := complex(float64(-6), 2)
+	nv2 := (*complex128)(nil)
+	pv2 := &v2
+	v2Addr := fmt.Sprintf("%p", pv2)
+	pv2Addr := fmt.Sprintf("%p", &pv2)
+	v2t := "complex128"
+	v2s := "(-6+2i)"
+	addFormatterTest("%v", v2, v2s)
+	addFormatterTest("%v", pv2, "<*>"+v2s)
+	addFormatterTest("%v", &pv2, "<**>"+v2s)
+	addFormatterTest("%+v", nv2, "<nil>")
+	addFormatterTest("%+v", v2, v2s)
+	addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+	addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+	addFormatterTest("%+v", nv2, "<nil>")
+	addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+	addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+	addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+	addFormatterTest("%#v", nv2, "(*"+v2t+")"+"<nil>")
+	addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+	addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+	addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+	addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"<nil>")
+}
+
+func addArrayFormatterTests() {
+	// Array containing standard ints.
+	v := [3]int{1, 2, 3}
+	nv := (*[3]int)(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vt := "[3]int"
+	vs := "[1 2 3]"
+	addFormatterTest("%v", v, vs)
+	addFormatterTest("%v", pv, "<*>"+vs)
+	addFormatterTest("%v", &pv, "<**>"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%+v", v, vs)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%#v", v, "("+vt+")"+vs)
+	addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+	addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+	addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+	addFormatterTest("%#+v", v, "("+vt+")"+vs)
+	addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+	addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+
+	// Array containing type with custom formatter on pointer receiver only.
+	v2 := [3]pstringer{"1", "2", "3"}
+	nv2 := (*[3]pstringer)(nil)
+	pv2 := &v2
+	v2Addr := fmt.Sprintf("%p", pv2)
+	pv2Addr := fmt.Sprintf("%p", &pv2)
+	v2t := "[3]spew_test.pstringer"
+	v2sp := "[stringer 1 stringer 2 stringer 3]"
+	v2s := v2sp
+	if spew.UnsafeDisabled {
+		v2s = "[1 2 3]"
+	}
+	addFormatterTest("%v", v2, v2s)
+	addFormatterTest("%v", pv2, "<*>"+v2sp)
+	addFormatterTest("%v", &pv2, "<**>"+v2sp)
+	addFormatterTest("%+v", nv2, "<nil>")
+	addFormatterTest("%+v", v2, v2s)
+	addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2sp)
+	addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2sp)
+	addFormatterTest("%+v", nv2, "<nil>")
+	addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+	addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2sp)
+	addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2sp)
+	addFormatterTest("%#v", nv2, "(*"+v2t+")"+"<nil>")
+	addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+	addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2sp)
+	addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2sp)
+	addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"<nil>")
+
+	// Array containing interfaces.
+	v3 := [3]interface{}{"one", int(2), uint(3)}
+	nv3 := (*[3]interface{})(nil)
+	pv3 := &v3
+	v3Addr := fmt.Sprintf("%p", pv3)
+	pv3Addr := fmt.Sprintf("%p", &pv3)
+	v3t := "[3]interface {}"
+	v3t2 := "string"
+	v3t3 := "int"
+	v3t4 := "uint"
+	v3s := "[one 2 3]"
+	v3s2 := "[(" + v3t2 + ")one (" + v3t3 + ")2 (" + v3t4 + ")3]"
+	addFormatterTest("%v", v3, v3s)
+	addFormatterTest("%v", pv3, "<*>"+v3s)
+	addFormatterTest("%v", &pv3, "<**>"+v3s)
+	addFormatterTest("%+v", nv3, "<nil>")
+	addFormatterTest("%+v", v3, v3s)
+	addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s)
+	addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s)
+	addFormatterTest("%+v", nv3, "<nil>")
+	addFormatterTest("%#v", v3, "("+v3t+")"+v3s2)
+	addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s2)
+	addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s2)
+	addFormatterTest("%#v", nv3, "(*"+v3t+")"+"<nil>")
+	addFormatterTest("%#+v", v3, "("+v3t+")"+v3s2)
+	addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s2)
+	addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s2)
+	addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"<nil>")
+}
+
+func addSliceFormatterTests() {
+	// Slice containing standard float32 values.
+	v := []float32{3.14, 6.28, 12.56}
+	nv := (*[]float32)(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vt := "[]float32"
+	vs := "[3.14 6.28 12.56]"
+	addFormatterTest("%v", v, vs)
+	addFormatterTest("%v", pv, "<*>"+vs)
+	addFormatterTest("%v", &pv, "<**>"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%+v", v, vs)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%#v", v, "("+vt+")"+vs)
+	addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+	addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+	addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+	addFormatterTest("%#+v", v, "("+vt+")"+vs)
+	addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+	addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+
+	// Slice containing type with custom formatter on pointer receiver only.
+	v2 := []pstringer{"1", "2", "3"}
+	nv2 := (*[]pstringer)(nil)
+	pv2 := &v2
+	v2Addr := fmt.Sprintf("%p", pv2)
+	pv2Addr := fmt.Sprintf("%p", &pv2)
+	v2t := "[]spew_test.pstringer"
+	v2s := "[stringer 1 stringer 2 stringer 3]"
+	addFormatterTest("%v", v2, v2s)
+	addFormatterTest("%v", pv2, "<*>"+v2s)
+	addFormatterTest("%v", &pv2, "<**>"+v2s)
+	addFormatterTest("%+v", nv2, "<nil>")
+	addFormatterTest("%+v", v2, v2s)
+	addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+	addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+	addFormatterTest("%+v", nv2, "<nil>")
+	addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+	addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+	addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+	addFormatterTest("%#v", nv2, "(*"+v2t+")"+"<nil>")
+	addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+	addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+	addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+	addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"<nil>")
+
+	// Slice containing interfaces.
+	v3 := []interface{}{"one", int(2), uint(3), nil}
+	nv3 := (*[]interface{})(nil)
+	pv3 := &v3
+	v3Addr := fmt.Sprintf("%p", pv3)
+	pv3Addr := fmt.Sprintf("%p", &pv3)
+	v3t := "[]interface {}"
+	v3t2 := "string"
+	v3t3 := "int"
+	v3t4 := "uint"
+	v3t5 := "interface {}"
+	v3s := "[one 2 3 <nil>]"
+	v3s2 := "[(" + v3t2 + ")one (" + v3t3 + ")2 (" + v3t4 + ")3 (" + v3t5 +
+		")<nil>]"
+	addFormatterTest("%v", v3, v3s)
+	addFormatterTest("%v", pv3, "<*>"+v3s)
+	addFormatterTest("%v", &pv3, "<**>"+v3s)
+	addFormatterTest("%+v", nv3, "<nil>")
+	addFormatterTest("%+v", v3, v3s)
+	addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s)
+	addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s)
+	addFormatterTest("%+v", nv3, "<nil>")
+	addFormatterTest("%#v", v3, "("+v3t+")"+v3s2)
+	addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s2)
+	addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s2)
+	addFormatterTest("%#v", nv3, "(*"+v3t+")"+"<nil>")
+	addFormatterTest("%#+v", v3, "("+v3t+")"+v3s2)
+	addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s2)
+	addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s2)
+	addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"<nil>")
+
+	// Nil slice.
+	var v4 []int
+	nv4 := (*[]int)(nil)
+	pv4 := &v4
+	v4Addr := fmt.Sprintf("%p", pv4)
+	pv4Addr := fmt.Sprintf("%p", &pv4)
+	v4t := "[]int"
+	v4s := "<nil>"
+	addFormatterTest("%v", v4, v4s)
+	addFormatterTest("%v", pv4, "<*>"+v4s)
+	addFormatterTest("%v", &pv4, "<**>"+v4s)
+	addFormatterTest("%+v", nv4, "<nil>")
+	addFormatterTest("%+v", v4, v4s)
+	addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s)
+	addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s)
+	addFormatterTest("%+v", nv4, "<nil>")
+	addFormatterTest("%#v", v4, "("+v4t+")"+v4s)
+	addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s)
+	addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s)
+	addFormatterTest("%#v", nv4, "(*"+v4t+")"+"<nil>")
+	addFormatterTest("%#+v", v4, "("+v4t+")"+v4s)
+	addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s)
+	addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s)
+	addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"<nil>")
+}
+
+func addStringFormatterTests() {
+	// Standard string.
+	v := "test"
+	nv := (*string)(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vt := "string"
+	vs := "test"
+	addFormatterTest("%v", v, vs)
+	addFormatterTest("%v", pv, "<*>"+vs)
+	addFormatterTest("%v", &pv, "<**>"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%+v", v, vs)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%#v", v, "("+vt+")"+vs)
+	addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+	addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+	addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+	addFormatterTest("%#+v", v, "("+vt+")"+vs)
+	addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+	addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+}
+
+func addInterfaceFormatterTests() {
+	// Nil interface.
+	var v interface{}
+	nv := (*interface{})(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vt := "interface {}"
+	vs := "<nil>"
+	addFormatterTest("%v", v, vs)
+	addFormatterTest("%v", pv, "<*>"+vs)
+	addFormatterTest("%v", &pv, "<**>"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%+v", v, vs)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%#v", v, "("+vt+")"+vs)
+	addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+	addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+	addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+	addFormatterTest("%#+v", v, "("+vt+")"+vs)
+	addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+	addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+
+	// Sub-interface.
+	v2 := interface{}(uint16(65535))
+	pv2 := &v2
+	v2Addr := fmt.Sprintf("%p", pv2)
+	pv2Addr := fmt.Sprintf("%p", &pv2)
+	v2t := "uint16"
+	v2s := "65535"
+	addFormatterTest("%v", v2, v2s)
+	addFormatterTest("%v", pv2, "<*>"+v2s)
+	addFormatterTest("%v", &pv2, "<**>"+v2s)
+	addFormatterTest("%+v", v2, v2s)
+	addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+	addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+	addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+	addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+	addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+	addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+	addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+	addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+}
+
+func addMapFormatterTests() {
+	// Map with string keys and int vals.
+	v := map[string]int{"one": 1, "two": 2}
+	nilMap := map[string]int(nil)
+	nv := (*map[string]int)(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vt := "map[string]int"
+	vs := "map[one:1 two:2]"
+	vs2 := "map[two:2 one:1]"
+	addFormatterTest("%v", v, vs, vs2)
+	addFormatterTest("%v", pv, "<*>"+vs, "<*>"+vs2)
+	addFormatterTest("%v", &pv, "<**>"+vs, "<**>"+vs2)
+	addFormatterTest("%+v", nilMap, "<nil>")
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%+v", v, vs, vs2)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs, "<*>("+vAddr+")"+vs2)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs,
+		"<**>("+pvAddr+"->"+vAddr+")"+vs2)
+	addFormatterTest("%+v", nilMap, "<nil>")
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%#v", v, "("+vt+")"+vs, "("+vt+")"+vs2)
+	addFormatterTest("%#v", pv, "(*"+vt+")"+vs, "(*"+vt+")"+vs2)
+	addFormatterTest("%#v", &pv, "(**"+vt+")"+vs, "(**"+vt+")"+vs2)
+	addFormatterTest("%#v", nilMap, "("+vt+")"+"<nil>")
+	addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+	addFormatterTest("%#+v", v, "("+vt+")"+vs, "("+vt+")"+vs2)
+	addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs,
+		"(*"+vt+")("+vAddr+")"+vs2)
+	addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs,
+		"(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs2)
+	addFormatterTest("%#+v", nilMap, "("+vt+")"+"<nil>")
+	addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+
+	// Map with custom formatter type on pointer receiver only keys and vals.
+	v2 := map[pstringer]pstringer{"one": "1"}
+	nv2 := (*map[pstringer]pstringer)(nil)
+	pv2 := &v2
+	v2Addr := fmt.Sprintf("%p", pv2)
+	pv2Addr := fmt.Sprintf("%p", &pv2)
+	v2t := "map[spew_test.pstringer]spew_test.pstringer"
+	v2s := "map[stringer one:stringer 1]"
+	if spew.UnsafeDisabled {
+		v2s = "map[one:1]"
+	}
+	addFormatterTest("%v", v2, v2s)
+	addFormatterTest("%v", pv2, "<*>"+v2s)
+	addFormatterTest("%v", &pv2, "<**>"+v2s)
+	addFormatterTest("%+v", nv2, "<nil>")
+	addFormatterTest("%+v", v2, v2s)
+	addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+	addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+	addFormatterTest("%+v", nv2, "<nil>")
+	addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+	addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+	addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+	addFormatterTest("%#v", nv2, "(*"+v2t+")"+"<nil>")
+	addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+	addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+	addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+	addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"<nil>")
+
+	// Map with interface keys and values.
+	v3 := map[interface{}]interface{}{"one": 1}
+	nv3 := (*map[interface{}]interface{})(nil)
+	pv3 := &v3
+	v3Addr := fmt.Sprintf("%p", pv3)
+	pv3Addr := fmt.Sprintf("%p", &pv3)
+	v3t := "map[interface {}]interface {}"
+	v3t1 := "string"
+	v3t2 := "int"
+	v3s := "map[one:1]"
+	v3s2 := "map[(" + v3t1 + ")one:(" + v3t2 + ")1]"
+	addFormatterTest("%v", v3, v3s)
+	addFormatterTest("%v", pv3, "<*>"+v3s)
+	addFormatterTest("%v", &pv3, "<**>"+v3s)
+	addFormatterTest("%+v", nv3, "<nil>")
+	addFormatterTest("%+v", v3, v3s)
+	addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s)
+	addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s)
+	addFormatterTest("%+v", nv3, "<nil>")
+	addFormatterTest("%#v", v3, "("+v3t+")"+v3s2)
+	addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s2)
+	addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s2)
+	addFormatterTest("%#v", nv3, "(*"+v3t+")"+"<nil>")
+	addFormatterTest("%#+v", v3, "("+v3t+")"+v3s2)
+	addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s2)
+	addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s2)
+	addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"<nil>")
+
+	// Map with nil interface value
+	v4 := map[string]interface{}{"nil": nil}
+	nv4 := (*map[string]interface{})(nil)
+	pv4 := &v4
+	v4Addr := fmt.Sprintf("%p", pv4)
+	pv4Addr := fmt.Sprintf("%p", &pv4)
+	v4t := "map[string]interface {}"
+	v4t1 := "interface {}"
+	v4s := "map[nil:<nil>]"
+	v4s2 := "map[nil:(" + v4t1 + ")<nil>]"
+	addFormatterTest("%v", v4, v4s)
+	addFormatterTest("%v", pv4, "<*>"+v4s)
+	addFormatterTest("%v", &pv4, "<**>"+v4s)
+	addFormatterTest("%+v", nv4, "<nil>")
+	addFormatterTest("%+v", v4, v4s)
+	addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s)
+	addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s)
+	addFormatterTest("%+v", nv4, "<nil>")
+	addFormatterTest("%#v", v4, "("+v4t+")"+v4s2)
+	addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s2)
+	addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s2)
+	addFormatterTest("%#v", nv4, "(*"+v4t+")"+"<nil>")
+	addFormatterTest("%#+v", v4, "("+v4t+")"+v4s2)
+	addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s2)
+	addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s2)
+	addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"<nil>")
+}
+
+func addStructFormatterTests() {
+	// Struct with primitives.
+	type s1 struct {
+		a int8
+		b uint8
+	}
+	v := s1{127, 255}
+	nv := (*s1)(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vt := "spew_test.s1"
+	vt2 := "int8"
+	vt3 := "uint8"
+	vs := "{127 255}"
+	vs2 := "{a:127 b:255}"
+	vs3 := "{a:(" + vt2 + ")127 b:(" + vt3 + ")255}"
+	addFormatterTest("%v", v, vs)
+	addFormatterTest("%v", pv, "<*>"+vs)
+	addFormatterTest("%v", &pv, "<**>"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%+v", v, vs2)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs2)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs2)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%#v", v, "("+vt+")"+vs3)
+	addFormatterTest("%#v", pv, "(*"+vt+")"+vs3)
+	addFormatterTest("%#v", &pv, "(**"+vt+")"+vs3)
+	addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+	addFormatterTest("%#+v", v, "("+vt+")"+vs3)
+	addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs3)
+	addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs3)
+	addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+
+	// Struct that contains another struct.
+	type s2 struct {
+		s1 s1
+		b  bool
+	}
+	v2 := s2{s1{127, 255}, true}
+	nv2 := (*s2)(nil)
+	pv2 := &v2
+	v2Addr := fmt.Sprintf("%p", pv2)
+	pv2Addr := fmt.Sprintf("%p", &pv2)
+	v2t := "spew_test.s2"
+	v2t2 := "spew_test.s1"
+	v2t3 := "int8"
+	v2t4 := "uint8"
+	v2t5 := "bool"
+	v2s := "{{127 255} true}"
+	v2s2 := "{s1:{a:127 b:255} b:true}"
+	v2s3 := "{s1:(" + v2t2 + "){a:(" + v2t3 + ")127 b:(" + v2t4 + ")255} b:(" +
+		v2t5 + ")true}"
+	addFormatterTest("%v", v2, v2s)
+	addFormatterTest("%v", pv2, "<*>"+v2s)
+	addFormatterTest("%v", &pv2, "<**>"+v2s)
+	addFormatterTest("%+v", nv2, "<nil>")
+	addFormatterTest("%+v", v2, v2s2)
+	addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s2)
+	addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s2)
+	addFormatterTest("%+v", nv2, "<nil>")
+	addFormatterTest("%#v", v2, "("+v2t+")"+v2s3)
+	addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s3)
+	addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s3)
+	addFormatterTest("%#v", nv2, "(*"+v2t+")"+"<nil>")
+	addFormatterTest("%#+v", v2, "("+v2t+")"+v2s3)
+	addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s3)
+	addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s3)
+	addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"<nil>")
+
+	// Struct that contains custom type with Stringer pointer interface via both
+	// exported and unexported fields.
+	type s3 struct {
+		s pstringer
+		S pstringer
+	}
+	v3 := s3{"test", "test2"}
+	nv3 := (*s3)(nil)
+	pv3 := &v3
+	v3Addr := fmt.Sprintf("%p", pv3)
+	pv3Addr := fmt.Sprintf("%p", &pv3)
+	v3t := "spew_test.s3"
+	v3t2 := "spew_test.pstringer"
+	v3s := "{stringer test stringer test2}"
+	v3sp := v3s
+	v3s2 := "{s:stringer test S:stringer test2}"
+	v3s2p := v3s2
+	v3s3 := "{s:(" + v3t2 + ")stringer test S:(" + v3t2 + ")stringer test2}"
+	v3s3p := v3s3
+	if spew.UnsafeDisabled {
+		v3s = "{test test2}"
+		v3sp = "{test stringer test2}"
+		v3s2 = "{s:test S:test2}"
+		v3s2p = "{s:test S:stringer test2}"
+		v3s3 = "{s:(" + v3t2 + ")test S:(" + v3t2 + ")test2}"
+		v3s3p = "{s:(" + v3t2 + ")test S:(" + v3t2 + ")stringer test2}"
+	}
+	addFormatterTest("%v", v3, v3s)
+	addFormatterTest("%v", pv3, "<*>"+v3sp)
+	addFormatterTest("%v", &pv3, "<**>"+v3sp)
+	addFormatterTest("%+v", nv3, "<nil>")
+	addFormatterTest("%+v", v3, v3s2)
+	addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s2p)
+	addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s2p)
+	addFormatterTest("%+v", nv3, "<nil>")
+	addFormatterTest("%#v", v3, "("+v3t+")"+v3s3)
+	addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s3p)
+	addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s3p)
+	addFormatterTest("%#v", nv3, "(*"+v3t+")"+"<nil>")
+	addFormatterTest("%#+v", v3, "("+v3t+")"+v3s3)
+	addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s3p)
+	addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s3p)
+	addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"<nil>")
+
+	// Struct that contains embedded struct and field to same struct.
+	e := embed{"embedstr"}
+	v4 := embedwrap{embed: &e, e: &e}
+	nv4 := (*embedwrap)(nil)
+	pv4 := &v4
+	eAddr := fmt.Sprintf("%p", &e)
+	v4Addr := fmt.Sprintf("%p", pv4)
+	pv4Addr := fmt.Sprintf("%p", &pv4)
+	v4t := "spew_test.embedwrap"
+	v4t2 := "spew_test.embed"
+	v4t3 := "string"
+	v4s := "{<*>{embedstr} <*>{embedstr}}"
+	v4s2 := "{embed:<*>(" + eAddr + "){a:embedstr} e:<*>(" + eAddr +
+		"){a:embedstr}}"
+	v4s3 := "{embed:(*" + v4t2 + "){a:(" + v4t3 + ")embedstr} e:(*" + v4t2 +
+		"){a:(" + v4t3 + ")embedstr}}"
+	v4s4 := "{embed:(*" + v4t2 + ")(" + eAddr + "){a:(" + v4t3 +
+		")embedstr} e:(*" + v4t2 + ")(" + eAddr + "){a:(" + v4t3 + ")embedstr}}"
+	addFormatterTest("%v", v4, v4s)
+	addFormatterTest("%v", pv4, "<*>"+v4s)
+	addFormatterTest("%v", &pv4, "<**>"+v4s)
+	addFormatterTest("%+v", nv4, "<nil>")
+	addFormatterTest("%+v", v4, v4s2)
+	addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s2)
+	addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s2)
+	addFormatterTest("%+v", nv4, "<nil>")
+	addFormatterTest("%#v", v4, "("+v4t+")"+v4s3)
+	addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s3)
+	addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s3)
+	addFormatterTest("%#v", nv4, "(*"+v4t+")"+"<nil>")
+	addFormatterTest("%#+v", v4, "("+v4t+")"+v4s4)
+	addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s4)
+	addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s4)
+	addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"<nil>")
+}
+
+func addUintptrFormatterTests() {
+	// Null pointer.
+	v := uintptr(0)
+	nv := (*uintptr)(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vt := "uintptr"
+	vs := "<nil>"
+	addFormatterTest("%v", v, vs)
+	addFormatterTest("%v", pv, "<*>"+vs)
+	addFormatterTest("%v", &pv, "<**>"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%+v", v, vs)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%#v", v, "("+vt+")"+vs)
+	addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+	addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+	addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+	addFormatterTest("%#+v", v, "("+vt+")"+vs)
+	addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+	addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+
+	// Address of real variable.
+	i := 1
+	v2 := uintptr(unsafe.Pointer(&i))
+	pv2 := &v2
+	v2Addr := fmt.Sprintf("%p", pv2)
+	pv2Addr := fmt.Sprintf("%p", &pv2)
+	v2t := "uintptr"
+	v2s := fmt.Sprintf("%p", &i)
+	addFormatterTest("%v", v2, v2s)
+	addFormatterTest("%v", pv2, "<*>"+v2s)
+	addFormatterTest("%v", &pv2, "<**>"+v2s)
+	addFormatterTest("%+v", v2, v2s)
+	addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+	addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+	addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+	addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+	addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+	addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+	addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+	addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+}
+
+func addUnsafePointerFormatterTests() {
+	// Null pointer.
+	v := unsafe.Pointer(uintptr(0))
+	nv := (*unsafe.Pointer)(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vt := "unsafe.Pointer"
+	vs := "<nil>"
+	addFormatterTest("%v", v, vs)
+	addFormatterTest("%v", pv, "<*>"+vs)
+	addFormatterTest("%v", &pv, "<**>"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%+v", v, vs)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%#v", v, "("+vt+")"+vs)
+	addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+	addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+	addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+	addFormatterTest("%#+v", v, "("+vt+")"+vs)
+	addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+	addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+
+	// Address of real variable.
+	i := 1
+	v2 := unsafe.Pointer(&i)
+	pv2 := &v2
+	v2Addr := fmt.Sprintf("%p", pv2)
+	pv2Addr := fmt.Sprintf("%p", &pv2)
+	v2t := "unsafe.Pointer"
+	v2s := fmt.Sprintf("%p", &i)
+	addFormatterTest("%v", v2, v2s)
+	addFormatterTest("%v", pv2, "<*>"+v2s)
+	addFormatterTest("%v", &pv2, "<**>"+v2s)
+	addFormatterTest("%+v", v2, v2s)
+	addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+	addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+	addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+	addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+	addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+	addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+	addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+	addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+}
+
+func addChanFormatterTests() {
+	// Nil channel.
+	var v chan int
+	pv := &v
+	nv := (*chan int)(nil)
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vt := "chan int"
+	vs := "<nil>"
+	addFormatterTest("%v", v, vs)
+	addFormatterTest("%v", pv, "<*>"+vs)
+	addFormatterTest("%v", &pv, "<**>"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%+v", v, vs)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%#v", v, "("+vt+")"+vs)
+	addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+	addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+	addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+	addFormatterTest("%#+v", v, "("+vt+")"+vs)
+	addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+	addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+
+	// Real channel.
+	v2 := make(chan int)
+	pv2 := &v2
+	v2Addr := fmt.Sprintf("%p", pv2)
+	pv2Addr := fmt.Sprintf("%p", &pv2)
+	v2t := "chan int"
+	v2s := fmt.Sprintf("%p", v2)
+	addFormatterTest("%v", v2, v2s)
+	addFormatterTest("%v", pv2, "<*>"+v2s)
+	addFormatterTest("%v", &pv2, "<**>"+v2s)
+	addFormatterTest("%+v", v2, v2s)
+	addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+	addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+	addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+	addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+	addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+	addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+	addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+	addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+}
+
+func addFuncFormatterTests() {
+	// Function with no params and no returns.
+	v := addIntFormatterTests
+	nv := (*func())(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vt := "func()"
+	vs := fmt.Sprintf("%p", v)
+	addFormatterTest("%v", v, vs)
+	addFormatterTest("%v", pv, "<*>"+vs)
+	addFormatterTest("%v", &pv, "<**>"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%+v", v, vs)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%#v", v, "("+vt+")"+vs)
+	addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+	addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+	addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+	addFormatterTest("%#+v", v, "("+vt+")"+vs)
+	addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+	addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+
+	// Function with param and no returns.
+	v2 := TestFormatter
+	nv2 := (*func(*testing.T))(nil)
+	pv2 := &v2
+	v2Addr := fmt.Sprintf("%p", pv2)
+	pv2Addr := fmt.Sprintf("%p", &pv2)
+	v2t := "func(*testing.T)"
+	v2s := fmt.Sprintf("%p", v2)
+	addFormatterTest("%v", v2, v2s)
+	addFormatterTest("%v", pv2, "<*>"+v2s)
+	addFormatterTest("%v", &pv2, "<**>"+v2s)
+	addFormatterTest("%+v", nv2, "<nil>")
+	addFormatterTest("%+v", v2, v2s)
+	addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+	addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+	addFormatterTest("%+v", nv2, "<nil>")
+	addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+	addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+	addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+	addFormatterTest("%#v", nv2, "(*"+v2t+")"+"<nil>")
+	addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+	addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+	addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+	addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"<nil>")
+
+	// Function with multiple params and multiple returns.
+	var v3 = func(i int, s string) (b bool, err error) {
+		return true, nil
+	}
+	nv3 := (*func(int, string) (bool, error))(nil)
+	pv3 := &v3
+	v3Addr := fmt.Sprintf("%p", pv3)
+	pv3Addr := fmt.Sprintf("%p", &pv3)
+	v3t := "func(int, string) (bool, error)"
+	v3s := fmt.Sprintf("%p", v3)
+	addFormatterTest("%v", v3, v3s)
+	addFormatterTest("%v", pv3, "<*>"+v3s)
+	addFormatterTest("%v", &pv3, "<**>"+v3s)
+	addFormatterTest("%+v", nv3, "<nil>")
+	addFormatterTest("%+v", v3, v3s)
+	addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s)
+	addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s)
+	addFormatterTest("%+v", nv3, "<nil>")
+	addFormatterTest("%#v", v3, "("+v3t+")"+v3s)
+	addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s)
+	addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s)
+	addFormatterTest("%#v", nv3, "(*"+v3t+")"+"<nil>")
+	addFormatterTest("%#+v", v3, "("+v3t+")"+v3s)
+	addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s)
+	addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s)
+	addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"<nil>")
+}
+
+func addCircularFormatterTests() {
+	// Struct that is circular through self referencing.
+	type circular struct {
+		c *circular
+	}
+	v := circular{nil}
+	v.c = &v
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vt := "spew_test.circular"
+	vs := "{<*>{<*><shown>}}"
+	vs2 := "{<*><shown>}"
+	vs3 := "{c:<*>(" + vAddr + "){c:<*>(" + vAddr + ")<shown>}}"
+	vs4 := "{c:<*>(" + vAddr + ")<shown>}"
+	vs5 := "{c:(*" + vt + "){c:(*" + vt + ")<shown>}}"
+	vs6 := "{c:(*" + vt + ")<shown>}"
+	vs7 := "{c:(*" + vt + ")(" + vAddr + "){c:(*" + vt + ")(" + vAddr +
+		")<shown>}}"
+	vs8 := "{c:(*" + vt + ")(" + vAddr + ")<shown>}"
+	addFormatterTest("%v", v, vs)
+	addFormatterTest("%v", pv, "<*>"+vs2)
+	addFormatterTest("%v", &pv, "<**>"+vs2)
+	addFormatterTest("%+v", v, vs3)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs4)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs4)
+	addFormatterTest("%#v", v, "("+vt+")"+vs5)
+	addFormatterTest("%#v", pv, "(*"+vt+")"+vs6)
+	addFormatterTest("%#v", &pv, "(**"+vt+")"+vs6)
+	addFormatterTest("%#+v", v, "("+vt+")"+vs7)
+	addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs8)
+	addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs8)
+
+	// Structs that are circular through cross referencing.
+	v2 := xref1{nil}
+	ts2 := xref2{&v2}
+	v2.ps2 = &ts2
+	pv2 := &v2
+	ts2Addr := fmt.Sprintf("%p", &ts2)
+	v2Addr := fmt.Sprintf("%p", pv2)
+	pv2Addr := fmt.Sprintf("%p", &pv2)
+	v2t := "spew_test.xref1"
+	v2t2 := "spew_test.xref2"
+	v2s := "{<*>{<*>{<*><shown>}}}"
+	v2s2 := "{<*>{<*><shown>}}"
+	v2s3 := "{ps2:<*>(" + ts2Addr + "){ps1:<*>(" + v2Addr + "){ps2:<*>(" +
+		ts2Addr + ")<shown>}}}"
+	v2s4 := "{ps2:<*>(" + ts2Addr + "){ps1:<*>(" + v2Addr + ")<shown>}}"
+	v2s5 := "{ps2:(*" + v2t2 + "){ps1:(*" + v2t + "){ps2:(*" + v2t2 +
+		")<shown>}}}"
+	v2s6 := "{ps2:(*" + v2t2 + "){ps1:(*" + v2t + ")<shown>}}"
+	v2s7 := "{ps2:(*" + v2t2 + ")(" + ts2Addr + "){ps1:(*" + v2t +
+		")(" + v2Addr + "){ps2:(*" + v2t2 + ")(" + ts2Addr +
+		")<shown>}}}"
+	v2s8 := "{ps2:(*" + v2t2 + ")(" + ts2Addr + "){ps1:(*" + v2t +
+		")(" + v2Addr + ")<shown>}}"
+	addFormatterTest("%v", v2, v2s)
+	addFormatterTest("%v", pv2, "<*>"+v2s2)
+	addFormatterTest("%v", &pv2, "<**>"+v2s2)
+	addFormatterTest("%+v", v2, v2s3)
+	addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s4)
+	addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s4)
+	addFormatterTest("%#v", v2, "("+v2t+")"+v2s5)
+	addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s6)
+	addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s6)
+	addFormatterTest("%#+v", v2, "("+v2t+")"+v2s7)
+	addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s8)
+	addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s8)
+
+	// Structs that are indirectly circular.
+	v3 := indirCir1{nil}
+	tic2 := indirCir2{nil}
+	tic3 := indirCir3{&v3}
+	tic2.ps3 = &tic3
+	v3.ps2 = &tic2
+	pv3 := &v3
+	tic2Addr := fmt.Sprintf("%p", &tic2)
+	tic3Addr := fmt.Sprintf("%p", &tic3)
+	v3Addr := fmt.Sprintf("%p", pv3)
+	pv3Addr := fmt.Sprintf("%p", &pv3)
+	v3t := "spew_test.indirCir1"
+	v3t2 := "spew_test.indirCir2"
+	v3t3 := "spew_test.indirCir3"
+	v3s := "{<*>{<*>{<*>{<*><shown>}}}}"
+	v3s2 := "{<*>{<*>{<*><shown>}}}"
+	v3s3 := "{ps2:<*>(" + tic2Addr + "){ps3:<*>(" + tic3Addr + "){ps1:<*>(" +
+		v3Addr + "){ps2:<*>(" + tic2Addr + ")<shown>}}}}"
+	v3s4 := "{ps2:<*>(" + tic2Addr + "){ps3:<*>(" + tic3Addr + "){ps1:<*>(" +
+		v3Addr + ")<shown>}}}"
+	v3s5 := "{ps2:(*" + v3t2 + "){ps3:(*" + v3t3 + "){ps1:(*" + v3t +
+		"){ps2:(*" + v3t2 + ")<shown>}}}}"
+	v3s6 := "{ps2:(*" + v3t2 + "){ps3:(*" + v3t3 + "){ps1:(*" + v3t +
+		")<shown>}}}"
+	v3s7 := "{ps2:(*" + v3t2 + ")(" + tic2Addr + "){ps3:(*" + v3t3 + ")(" +
+		tic3Addr + "){ps1:(*" + v3t + ")(" + v3Addr + "){ps2:(*" + v3t2 +
+		")(" + tic2Addr + ")<shown>}}}}"
+	v3s8 := "{ps2:(*" + v3t2 + ")(" + tic2Addr + "){ps3:(*" + v3t3 + ")(" +
+		tic3Addr + "){ps1:(*" + v3t + ")(" + v3Addr + ")<shown>}}}"
+	addFormatterTest("%v", v3, v3s)
+	addFormatterTest("%v", pv3, "<*>"+v3s2)
+	addFormatterTest("%v", &pv3, "<**>"+v3s2)
+	addFormatterTest("%+v", v3, v3s3)
+	addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s4)
+	addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s4)
+	addFormatterTest("%#v", v3, "("+v3t+")"+v3s5)
+	addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s6)
+	addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s6)
+	addFormatterTest("%#+v", v3, "("+v3t+")"+v3s7)
+	addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s8)
+	addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s8)
+}
+
+func addPanicFormatterTests() {
+	// Type that panics in its Stringer interface.
+	v := panicer(127)
+	nv := (*panicer)(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vt := "spew_test.panicer"
+	vs := "(PANIC=test panic)127"
+	addFormatterTest("%v", v, vs)
+	addFormatterTest("%v", pv, "<*>"+vs)
+	addFormatterTest("%v", &pv, "<**>"+vs)
+	addFormatterTest("%v", nv, "<nil>")
+	addFormatterTest("%+v", v, vs)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%#v", v, "("+vt+")"+vs)
+	addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+	addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+	addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+	addFormatterTest("%#+v", v, "("+vt+")"+vs)
+	addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+	addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+}
+
+func addErrorFormatterTests() {
+	// Type that has a custom Error interface.
+	v := customError(127)
+	nv := (*customError)(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vt := "spew_test.customError"
+	vs := "error: 127"
+	addFormatterTest("%v", v, vs)
+	addFormatterTest("%v", pv, "<*>"+vs)
+	addFormatterTest("%v", &pv, "<**>"+vs)
+	addFormatterTest("%v", nv, "<nil>")
+	addFormatterTest("%+v", v, vs)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%#v", v, "("+vt+")"+vs)
+	addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+	addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+	addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+	addFormatterTest("%#+v", v, "("+vt+")"+vs)
+	addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+	addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+}
+
+func addPassthroughFormatterTests() {
+	// %x passthrough with uint.
+	v := uint(4294967295)
+	pv := &v
+	vAddr := fmt.Sprintf("%x", pv)
+	pvAddr := fmt.Sprintf("%x", &pv)
+	vs := "ffffffff"
+	addFormatterTest("%x", v, vs)
+	addFormatterTest("%x", pv, vAddr)
+	addFormatterTest("%x", &pv, pvAddr)
+
+	// %#x passthrough with uint.
+	v2 := int(2147483647)
+	pv2 := &v2
+	v2Addr := fmt.Sprintf("%#x", pv2)
+	pv2Addr := fmt.Sprintf("%#x", &pv2)
+	v2s := "0x7fffffff"
+	addFormatterTest("%#x", v2, v2s)
+	addFormatterTest("%#x", pv2, v2Addr)
+	addFormatterTest("%#x", &pv2, pv2Addr)
+
+	// %f passthrough with precision.
+	addFormatterTest("%.2f", 3.1415, "3.14")
+	addFormatterTest("%.3f", 3.1415, "3.142")
+	addFormatterTest("%.4f", 3.1415, "3.1415")
+
+	// %f passthrough with width and precision.
+	addFormatterTest("%5.2f", 3.1415, " 3.14")
+	addFormatterTest("%6.3f", 3.1415, " 3.142")
+	addFormatterTest("%7.4f", 3.1415, " 3.1415")
+
+	// %d passthrough with width.
+	addFormatterTest("%3d", 127, "127")
+	addFormatterTest("%4d", 127, " 127")
+	addFormatterTest("%5d", 127, "  127")
+
+	// %q passthrough with string.
+	addFormatterTest("%q", "test", "\"test\"")
+}
+
+// TestFormatter executes all of the tests described by formatterTests.
+func TestFormatter(t *testing.T) {
+	// Setup tests.
+	addIntFormatterTests()
+	addUintFormatterTests()
+	addBoolFormatterTests()
+	addFloatFormatterTests()
+	addComplexFormatterTests()
+	addArrayFormatterTests()
+	addSliceFormatterTests()
+	addStringFormatterTests()
+	addInterfaceFormatterTests()
+	addMapFormatterTests()
+	addStructFormatterTests()
+	addUintptrFormatterTests()
+	addUnsafePointerFormatterTests()
+	addChanFormatterTests()
+	addFuncFormatterTests()
+	addCircularFormatterTests()
+	addPanicFormatterTests()
+	addErrorFormatterTests()
+	addPassthroughFormatterTests()
+
+	t.Logf("Running %d tests", len(formatterTests))
+	for i, test := range formatterTests {
+		buf := new(bytes.Buffer)
+		spew.Fprintf(buf, test.format, test.in)
+		s := buf.String()
+		if testFailed(s, test.wants) {
+			t.Errorf("Formatter #%d format: %s got: %s %s", i, test.format, s,
+				stringizeWants(test.wants))
+			continue
+		}
+	}
+}
+
+type testStruct struct {
+	x int
+}
+
+func (ts testStruct) String() string {
+	return fmt.Sprintf("ts.%d", ts.x)
+}
+
+type testStructP struct {
+	x int
+}
+
+func (ts *testStructP) String() string {
+	return fmt.Sprintf("ts.%d", ts.x)
+}
+
+func TestPrintSortedKeys(t *testing.T) {
+	cfg := spew.ConfigState{SortKeys: true}
+	s := cfg.Sprint(map[int]string{1: "1", 3: "3", 2: "2"})
+	expected := "map[1:1 2:2 3:3]"
+	if s != expected {
+		t.Errorf("Sorted keys mismatch 1:\n  %v %v", s, expected)
+	}
+
+	s = cfg.Sprint(map[stringer]int{"1": 1, "3": 3, "2": 2})
+	expected = "map[stringer 1:1 stringer 2:2 stringer 3:3]"
+	if s != expected {
+		t.Errorf("Sorted keys mismatch 2:\n  %v %v", s, expected)
+	}
+
+	s = cfg.Sprint(map[pstringer]int{pstringer("1"): 1, pstringer("3"): 3, pstringer("2"): 2})
+	expected = "map[stringer 1:1 stringer 2:2 stringer 3:3]"
+	if spew.UnsafeDisabled {
+		expected = "map[1:1 2:2 3:3]"
+	}
+	if s != expected {
+		t.Errorf("Sorted keys mismatch 3:\n  %v %v", s, expected)
+	}
+
+	s = cfg.Sprint(map[testStruct]int{testStruct{1}: 1, testStruct{3}: 3, testStruct{2}: 2})
+	expected = "map[ts.1:1 ts.2:2 ts.3:3]"
+	if s != expected {
+		t.Errorf("Sorted keys mismatch 4:\n  %v %v", s, expected)
+	}
+
+	if !spew.UnsafeDisabled {
+		s = cfg.Sprint(map[testStructP]int{testStructP{1}: 1, testStructP{3}: 3, testStructP{2}: 2})
+		expected = "map[ts.1:1 ts.2:2 ts.3:3]"
+		if s != expected {
+			t.Errorf("Sorted keys mismatch 5:\n  %v %v", s, expected)
+		}
+	}
+
+	s = cfg.Sprint(map[customError]int{customError(1): 1, customError(3): 3, customError(2): 2})
+	expected = "map[error: 1:1 error: 2:2 error: 3:3]"
+	if s != expected {
+		t.Errorf("Sorted keys mismatch 6:\n  %v %v", s, expected)
+	}
+}

+ 87 - 0
vendor/github.com/davecgh/go-spew/spew/internal_test.go

@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+This test file is part of the spew package rather than than the spew_test
+package because it needs access to internals to properly test certain cases
+which are not possible via the public interface since they should never happen.
+*/
+
+package spew
+
+import (
+	"bytes"
+	"reflect"
+	"testing"
+)
+
+// dummyFmtState implements a fake fmt.State to use for testing invalid
+// reflect.Value handling.  This is necessary because the fmt package catches
+// invalid values before invoking the formatter on them.
+type dummyFmtState struct {
+	bytes.Buffer
+}
+
+func (dfs *dummyFmtState) Flag(f int) bool {
+	if f == int('+') {
+		return true
+	}
+	return false
+}
+
+func (dfs *dummyFmtState) Precision() (int, bool) {
+	return 0, false
+}
+
+func (dfs *dummyFmtState) Width() (int, bool) {
+	return 0, false
+}
+
+// TestInvalidReflectValue ensures the dump and formatter code handles an
+// invalid reflect value properly.  This needs access to internal state since it
+// should never happen in real code and therefore can't be tested via the public
+// API.
+func TestInvalidReflectValue(t *testing.T) {
+	i := 1
+
+	// Dump invalid reflect value.
+	v := new(reflect.Value)
+	buf := new(bytes.Buffer)
+	d := dumpState{w: buf, cs: &Config}
+	d.dump(*v)
+	s := buf.String()
+	want := "<invalid>"
+	if s != want {
+		t.Errorf("InvalidReflectValue #%d\n got: %s want: %s", i, s, want)
+	}
+	i++
+
+	// Formatter invalid reflect value.
+	buf2 := new(dummyFmtState)
+	f := formatState{value: *v, cs: &Config, fs: buf2}
+	f.format(*v)
+	s = buf2.String()
+	want = "<invalid>"
+	if s != want {
+		t.Errorf("InvalidReflectValue #%d got: %s want: %s", i, s, want)
+	}
+}
+
+// SortValues makes the internal sortValues function available to the test
+// package.
+func SortValues(values []reflect.Value, cs *ConfigState) {
+	sortValues(values, cs)
+}

+ 102 - 0
vendor/github.com/davecgh/go-spew/spew/internalunsafe_test.go

@@ -0,0 +1,102 @@
+// Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
+
+// Permission to use, copy, modify, and distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+// NOTE: Due to the following build constraints, this file will only be compiled
+// when the code is not running on Google App Engine, compiled by GopherJS, and
+// "-tags safe" is not added to the go build command line.  The "disableunsafe"
+// tag is deprecated and thus should not be used.
+// +build !js,!appengine,!safe,!disableunsafe
+
+/*
+This test file is part of the spew package rather than than the spew_test
+package because it needs access to internals to properly test certain cases
+which are not possible via the public interface since they should never happen.
+*/
+
+package spew
+
+import (
+	"bytes"
+	"reflect"
+	"testing"
+	"unsafe"
+)
+
+// changeKind uses unsafe to intentionally change the kind of a reflect.Value to
+// the maximum kind value which does not exist.  This is needed to test the
+// fallback code which punts to the standard fmt library for new types that
+// might get added to the language.
+func changeKind(v *reflect.Value, readOnly bool) {
+	rvf := (*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + offsetFlag))
+	*rvf = *rvf | ((1<<flagKindWidth - 1) << flagKindShift)
+	if readOnly {
+		*rvf |= flagRO
+	} else {
+		*rvf &= ^uintptr(flagRO)
+	}
+}
+
+// TestAddedReflectValue tests functionaly of the dump and formatter code which
+// falls back to the standard fmt library for new types that might get added to
+// the language.
+func TestAddedReflectValue(t *testing.T) {
+	i := 1
+
+	// Dump using a reflect.Value that is exported.
+	v := reflect.ValueOf(int8(5))
+	changeKind(&v, false)
+	buf := new(bytes.Buffer)
+	d := dumpState{w: buf, cs: &Config}
+	d.dump(v)
+	s := buf.String()
+	want := "(int8) 5"
+	if s != want {
+		t.Errorf("TestAddedReflectValue #%d\n got: %s want: %s", i, s, want)
+	}
+	i++
+
+	// Dump using a reflect.Value that is not exported.
+	changeKind(&v, true)
+	buf.Reset()
+	d.dump(v)
+	s = buf.String()
+	want = "(int8) <int8 Value>"
+	if s != want {
+		t.Errorf("TestAddedReflectValue #%d\n got: %s want: %s", i, s, want)
+	}
+	i++
+
+	// Formatter using a reflect.Value that is exported.
+	changeKind(&v, false)
+	buf2 := new(dummyFmtState)
+	f := formatState{value: v, cs: &Config, fs: buf2}
+	f.format(v)
+	s = buf2.String()
+	want = "5"
+	if s != want {
+		t.Errorf("TestAddedReflectValue #%d got: %s want: %s", i, s, want)
+	}
+	i++
+
+	// Formatter using a reflect.Value that is not exported.
+	changeKind(&v, true)
+	buf2.Reset()
+	f = formatState{value: v, cs: &Config, fs: buf2}
+	f.format(v)
+	s = buf2.String()
+	want = "<int8 Value>"
+	if s != want {
+		t.Errorf("TestAddedReflectValue #%d got: %s want: %s", i, s, want)
+	}
+}

+ 320 - 0
vendor/github.com/davecgh/go-spew/spew/spew_test.go

@@ -0,0 +1,320 @@
+/*
+ * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+package spew_test
+
+import (
+	"bytes"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"testing"
+
+	"github.com/davecgh/go-spew/spew"
+)
+
+// spewFunc is used to identify which public function of the spew package or
+// ConfigState a test applies to.
+type spewFunc int
+
+const (
+	fCSFdump spewFunc = iota
+	fCSFprint
+	fCSFprintf
+	fCSFprintln
+	fCSPrint
+	fCSPrintln
+	fCSSdump
+	fCSSprint
+	fCSSprintf
+	fCSSprintln
+	fCSErrorf
+	fCSNewFormatter
+	fErrorf
+	fFprint
+	fFprintln
+	fPrint
+	fPrintln
+	fSdump
+	fSprint
+	fSprintf
+	fSprintln
+)
+
+// Map of spewFunc values to names for pretty printing.
+var spewFuncStrings = map[spewFunc]string{
+	fCSFdump:        "ConfigState.Fdump",
+	fCSFprint:       "ConfigState.Fprint",
+	fCSFprintf:      "ConfigState.Fprintf",
+	fCSFprintln:     "ConfigState.Fprintln",
+	fCSSdump:        "ConfigState.Sdump",
+	fCSPrint:        "ConfigState.Print",
+	fCSPrintln:      "ConfigState.Println",
+	fCSSprint:       "ConfigState.Sprint",
+	fCSSprintf:      "ConfigState.Sprintf",
+	fCSSprintln:     "ConfigState.Sprintln",
+	fCSErrorf:       "ConfigState.Errorf",
+	fCSNewFormatter: "ConfigState.NewFormatter",
+	fErrorf:         "spew.Errorf",
+	fFprint:         "spew.Fprint",
+	fFprintln:       "spew.Fprintln",
+	fPrint:          "spew.Print",
+	fPrintln:        "spew.Println",
+	fSdump:          "spew.Sdump",
+	fSprint:         "spew.Sprint",
+	fSprintf:        "spew.Sprintf",
+	fSprintln:       "spew.Sprintln",
+}
+
+func (f spewFunc) String() string {
+	if s, ok := spewFuncStrings[f]; ok {
+		return s
+	}
+	return fmt.Sprintf("Unknown spewFunc (%d)", int(f))
+}
+
+// spewTest is used to describe a test to be performed against the public
+// functions of the spew package or ConfigState.
+type spewTest struct {
+	cs     *spew.ConfigState
+	f      spewFunc
+	format string
+	in     interface{}
+	want   string
+}
+
+// spewTests houses the tests to be performed against the public functions of
+// the spew package and ConfigState.
+//
+// These tests are only intended to ensure the public functions are exercised
+// and are intentionally not exhaustive of types.  The exhaustive type
+// tests are handled in the dump and format tests.
+var spewTests []spewTest
+
+// redirStdout is a helper function to return the standard output from f as a
+// byte slice.
+func redirStdout(f func()) ([]byte, error) {
+	tempFile, err := ioutil.TempFile("", "ss-test")
+	if err != nil {
+		return nil, err
+	}
+	fileName := tempFile.Name()
+	defer os.Remove(fileName) // Ignore error
+
+	origStdout := os.Stdout
+	os.Stdout = tempFile
+	f()
+	os.Stdout = origStdout
+	tempFile.Close()
+
+	return ioutil.ReadFile(fileName)
+}
+
+func initSpewTests() {
+	// Config states with various settings.
+	scsDefault := spew.NewDefaultConfig()
+	scsNoMethods := &spew.ConfigState{Indent: " ", DisableMethods: true}
+	scsNoPmethods := &spew.ConfigState{Indent: " ", DisablePointerMethods: true}
+	scsMaxDepth := &spew.ConfigState{Indent: " ", MaxDepth: 1}
+	scsContinue := &spew.ConfigState{Indent: " ", ContinueOnMethod: true}
+	scsNoPtrAddr := &spew.ConfigState{DisablePointerAddresses: true}
+	scsNoCap := &spew.ConfigState{DisableCapacities: true}
+
+	// Variables for tests on types which implement Stringer interface with and
+	// without a pointer receiver.
+	ts := stringer("test")
+	tps := pstringer("test")
+
+	type ptrTester struct {
+		s *struct{}
+	}
+	tptr := &ptrTester{s: &struct{}{}}
+
+	// depthTester is used to test max depth handling for structs, array, slices
+	// and maps.
+	type depthTester struct {
+		ic    indirCir1
+		arr   [1]string
+		slice []string
+		m     map[string]int
+	}
+	dt := depthTester{indirCir1{nil}, [1]string{"arr"}, []string{"slice"},
+		map[string]int{"one": 1}}
+
+	// Variable for tests on types which implement error interface.
+	te := customError(10)
+
+	spewTests = []spewTest{
+		{scsDefault, fCSFdump, "", int8(127), "(int8) 127\n"},
+		{scsDefault, fCSFprint, "", int16(32767), "32767"},
+		{scsDefault, fCSFprintf, "%v", int32(2147483647), "2147483647"},
+		{scsDefault, fCSFprintln, "", int(2147483647), "2147483647\n"},
+		{scsDefault, fCSPrint, "", int64(9223372036854775807), "9223372036854775807"},
+		{scsDefault, fCSPrintln, "", uint8(255), "255\n"},
+		{scsDefault, fCSSdump, "", uint8(64), "(uint8) 64\n"},
+		{scsDefault, fCSSprint, "", complex(1, 2), "(1+2i)"},
+		{scsDefault, fCSSprintf, "%v", complex(float32(3), 4), "(3+4i)"},
+		{scsDefault, fCSSprintln, "", complex(float64(5), 6), "(5+6i)\n"},
+		{scsDefault, fCSErrorf, "%#v", uint16(65535), "(uint16)65535"},
+		{scsDefault, fCSNewFormatter, "%v", uint32(4294967295), "4294967295"},
+		{scsDefault, fErrorf, "%v", uint64(18446744073709551615), "18446744073709551615"},
+		{scsDefault, fFprint, "", float32(3.14), "3.14"},
+		{scsDefault, fFprintln, "", float64(6.28), "6.28\n"},
+		{scsDefault, fPrint, "", true, "true"},
+		{scsDefault, fPrintln, "", false, "false\n"},
+		{scsDefault, fSdump, "", complex(-10, -20), "(complex128) (-10-20i)\n"},
+		{scsDefault, fSprint, "", complex(-1, -2), "(-1-2i)"},
+		{scsDefault, fSprintf, "%v", complex(float32(-3), -4), "(-3-4i)"},
+		{scsDefault, fSprintln, "", complex(float64(-5), -6), "(-5-6i)\n"},
+		{scsNoMethods, fCSFprint, "", ts, "test"},
+		{scsNoMethods, fCSFprint, "", &ts, "<*>test"},
+		{scsNoMethods, fCSFprint, "", tps, "test"},
+		{scsNoMethods, fCSFprint, "", &tps, "<*>test"},
+		{scsNoPmethods, fCSFprint, "", ts, "stringer test"},
+		{scsNoPmethods, fCSFprint, "", &ts, "<*>stringer test"},
+		{scsNoPmethods, fCSFprint, "", tps, "test"},
+		{scsNoPmethods, fCSFprint, "", &tps, "<*>stringer test"},
+		{scsMaxDepth, fCSFprint, "", dt, "{{<max>} [<max>] [<max>] map[<max>]}"},
+		{scsMaxDepth, fCSFdump, "", dt, "(spew_test.depthTester) {\n" +
+			" ic: (spew_test.indirCir1) {\n  <max depth reached>\n },\n" +
+			" arr: ([1]string) (len=1 cap=1) {\n  <max depth reached>\n },\n" +
+			" slice: ([]string) (len=1 cap=1) {\n  <max depth reached>\n },\n" +
+			" m: (map[string]int) (len=1) {\n  <max depth reached>\n }\n}\n"},
+		{scsContinue, fCSFprint, "", ts, "(stringer test) test"},
+		{scsContinue, fCSFdump, "", ts, "(spew_test.stringer) " +
+			"(len=4) (stringer test) \"test\"\n"},
+		{scsContinue, fCSFprint, "", te, "(error: 10) 10"},
+		{scsContinue, fCSFdump, "", te, "(spew_test.customError) " +
+			"(error: 10) 10\n"},
+		{scsNoPtrAddr, fCSFprint, "", tptr, "<*>{<*>{}}"},
+		{scsNoPtrAddr, fCSSdump, "", tptr, "(*spew_test.ptrTester)({\ns: (*struct {})({\n})\n})\n"},
+		{scsNoCap, fCSSdump, "", make([]string, 0, 10), "([]string) {\n}\n"},
+		{scsNoCap, fCSSdump, "", make([]string, 1, 10), "([]string) (len=1) {\n(string) \"\"\n}\n"},
+	}
+}
+
+// TestSpew executes all of the tests described by spewTests.
+func TestSpew(t *testing.T) {
+	initSpewTests()
+
+	t.Logf("Running %d tests", len(spewTests))
+	for i, test := range spewTests {
+		buf := new(bytes.Buffer)
+		switch test.f {
+		case fCSFdump:
+			test.cs.Fdump(buf, test.in)
+
+		case fCSFprint:
+			test.cs.Fprint(buf, test.in)
+
+		case fCSFprintf:
+			test.cs.Fprintf(buf, test.format, test.in)
+
+		case fCSFprintln:
+			test.cs.Fprintln(buf, test.in)
+
+		case fCSPrint:
+			b, err := redirStdout(func() { test.cs.Print(test.in) })
+			if err != nil {
+				t.Errorf("%v #%d %v", test.f, i, err)
+				continue
+			}
+			buf.Write(b)
+
+		case fCSPrintln:
+			b, err := redirStdout(func() { test.cs.Println(test.in) })
+			if err != nil {
+				t.Errorf("%v #%d %v", test.f, i, err)
+				continue
+			}
+			buf.Write(b)
+
+		case fCSSdump:
+			str := test.cs.Sdump(test.in)
+			buf.WriteString(str)
+
+		case fCSSprint:
+			str := test.cs.Sprint(test.in)
+			buf.WriteString(str)
+
+		case fCSSprintf:
+			str := test.cs.Sprintf(test.format, test.in)
+			buf.WriteString(str)
+
+		case fCSSprintln:
+			str := test.cs.Sprintln(test.in)
+			buf.WriteString(str)
+
+		case fCSErrorf:
+			err := test.cs.Errorf(test.format, test.in)
+			buf.WriteString(err.Error())
+
+		case fCSNewFormatter:
+			fmt.Fprintf(buf, test.format, test.cs.NewFormatter(test.in))
+
+		case fErrorf:
+			err := spew.Errorf(test.format, test.in)
+			buf.WriteString(err.Error())
+
+		case fFprint:
+			spew.Fprint(buf, test.in)
+
+		case fFprintln:
+			spew.Fprintln(buf, test.in)
+
+		case fPrint:
+			b, err := redirStdout(func() { spew.Print(test.in) })
+			if err != nil {
+				t.Errorf("%v #%d %v", test.f, i, err)
+				continue
+			}
+			buf.Write(b)
+
+		case fPrintln:
+			b, err := redirStdout(func() { spew.Println(test.in) })
+			if err != nil {
+				t.Errorf("%v #%d %v", test.f, i, err)
+				continue
+			}
+			buf.Write(b)
+
+		case fSdump:
+			str := spew.Sdump(test.in)
+			buf.WriteString(str)
+
+		case fSprint:
+			str := spew.Sprint(test.in)
+			buf.WriteString(str)
+
+		case fSprintf:
+			str := spew.Sprintf(test.format, test.in)
+			buf.WriteString(str)
+
+		case fSprintln:
+			str := spew.Sprintln(test.in)
+			buf.WriteString(str)
+
+		default:
+			t.Errorf("%v #%d unrecognized function", test.f, i)
+			continue
+		}
+		s := buf.String()
+		if test.want != s {
+			t.Errorf("ConfigState #%d\n got: %s want: %s", i, s, test.want)
+			continue
+		}
+	}
+}

+ 82 - 0
vendor/github.com/davecgh/go-spew/spew/testdata/dumpcgo.go

@@ -0,0 +1,82 @@
+// Copyright (c) 2013 Dave Collins <dave@davec.name>
+//
+// Permission to use, copy, modify, and distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+// NOTE: Due to the following build constraints, this file will only be compiled
+// when both cgo is supported and "-tags testcgo" is added to the go test
+// command line.  This code should really only be in the dumpcgo_test.go file,
+// but unfortunately Go will not allow cgo in test files, so this is a
+// workaround to allow cgo types to be tested.  This configuration is used
+// because spew itself does not require cgo to run even though it does handle
+// certain cgo types specially.  Rather than forcing all clients to require cgo
+// and an external C compiler just to run the tests, this scheme makes them
+// optional.
+// +build cgo,testcgo
+
+package testdata
+
+/*
+#include <stdint.h>
+typedef unsigned char custom_uchar_t;
+
+char            *ncp = 0;
+char            *cp = "test";
+char             ca[6] = {'t', 'e', 's', 't', '2', '\0'};
+unsigned char    uca[6] = {'t', 'e', 's', 't', '3', '\0'};
+signed char      sca[6] = {'t', 'e', 's', 't', '4', '\0'};
+uint8_t          ui8ta[6] = {'t', 'e', 's', 't', '5', '\0'};
+custom_uchar_t   tuca[6] = {'t', 'e', 's', 't', '6', '\0'};
+*/
+import "C"
+
+// GetCgoNullCharPointer returns a null char pointer via cgo.  This is only
+// used for tests.
+func GetCgoNullCharPointer() interface{} {
+	return C.ncp
+}
+
+// GetCgoCharPointer returns a char pointer via cgo.  This is only used for
+// tests.
+func GetCgoCharPointer() interface{} {
+	return C.cp
+}
+
+// GetCgoCharArray returns a char array via cgo and the array's len and cap.
+// This is only used for tests.
+func GetCgoCharArray() (interface{}, int, int) {
+	return C.ca, len(C.ca), cap(C.ca)
+}
+
+// GetCgoUnsignedCharArray returns an unsigned char array via cgo and the
+// array's len and cap.  This is only used for tests.
+func GetCgoUnsignedCharArray() (interface{}, int, int) {
+	return C.uca, len(C.uca), cap(C.uca)
+}
+
+// GetCgoSignedCharArray returns a signed char array via cgo and the array's len
+// and cap.  This is only used for tests.
+func GetCgoSignedCharArray() (interface{}, int, int) {
+	return C.sca, len(C.sca), cap(C.sca)
+}
+
+// GetCgoUint8tArray returns a uint8_t array via cgo and the array's len and
+// cap.  This is only used for tests.
+func GetCgoUint8tArray() (interface{}, int, int) {
+	return C.ui8ta, len(C.ui8ta), cap(C.ui8ta)
+}
+
+// GetCgoTypdefedUnsignedCharArray returns a typedefed unsigned char array via
+// cgo and the array's len and cap.  This is only used for tests.
+func GetCgoTypdefedUnsignedCharArray() (interface{}, int, int) {
+	return C.tuca, len(C.tuca), cap(C.tuca)
+}

+ 61 - 0
vendor/github.com/davecgh/go-spew/test_coverage.txt

@@ -0,0 +1,61 @@
+
+github.com/davecgh/go-spew/spew/dump.go		 dumpState.dump			 100.00% (88/88)
+github.com/davecgh/go-spew/spew/format.go	 formatState.format		 100.00% (82/82)
+github.com/davecgh/go-spew/spew/format.go	 formatState.formatPtr		 100.00% (52/52)
+github.com/davecgh/go-spew/spew/dump.go		 dumpState.dumpPtr		 100.00% (44/44)
+github.com/davecgh/go-spew/spew/dump.go		 dumpState.dumpSlice		 100.00% (39/39)
+github.com/davecgh/go-spew/spew/common.go	 handleMethods			 100.00% (30/30)
+github.com/davecgh/go-spew/spew/common.go	 printHexPtr			 100.00% (18/18)
+github.com/davecgh/go-spew/spew/common.go	 unsafeReflectValue		 100.00% (13/13)
+github.com/davecgh/go-spew/spew/format.go	 formatState.constructOrigFormat 100.00% (12/12)
+github.com/davecgh/go-spew/spew/dump.go		 fdump				 100.00% (11/11)
+github.com/davecgh/go-spew/spew/format.go	 formatState.Format		 100.00% (11/11)
+github.com/davecgh/go-spew/spew/common.go	 init				 100.00% (10/10)
+github.com/davecgh/go-spew/spew/common.go	 printComplex			 100.00% (9/9)
+github.com/davecgh/go-spew/spew/common.go	 valuesSorter.Less		 100.00% (8/8)
+github.com/davecgh/go-spew/spew/format.go	 formatState.buildDefaultFormat	 100.00% (7/7)
+github.com/davecgh/go-spew/spew/format.go	 formatState.unpackValue	 100.00% (5/5)
+github.com/davecgh/go-spew/spew/dump.go		 dumpState.indent		 100.00% (4/4)
+github.com/davecgh/go-spew/spew/common.go	 catchPanic			 100.00% (4/4)
+github.com/davecgh/go-spew/spew/config.go	 ConfigState.convertArgs	 100.00% (4/4)
+github.com/davecgh/go-spew/spew/spew.go		 convertArgs			 100.00% (4/4)
+github.com/davecgh/go-spew/spew/format.go	 newFormatter			 100.00% (3/3)
+github.com/davecgh/go-spew/spew/dump.go		 Sdump				 100.00% (3/3)
+github.com/davecgh/go-spew/spew/common.go	 printBool			 100.00% (3/3)
+github.com/davecgh/go-spew/spew/common.go	 sortValues			 100.00% (3/3)
+github.com/davecgh/go-spew/spew/config.go	 ConfigState.Sdump		 100.00% (3/3)
+github.com/davecgh/go-spew/spew/dump.go		 dumpState.unpackValue		 100.00% (3/3)
+github.com/davecgh/go-spew/spew/spew.go		 Printf				 100.00% (1/1)
+github.com/davecgh/go-spew/spew/spew.go		 Println			 100.00% (1/1)
+github.com/davecgh/go-spew/spew/spew.go		 Sprint				 100.00% (1/1)
+github.com/davecgh/go-spew/spew/spew.go		 Sprintf			 100.00% (1/1)
+github.com/davecgh/go-spew/spew/spew.go		 Sprintln			 100.00% (1/1)
+github.com/davecgh/go-spew/spew/common.go	 printFloat			 100.00% (1/1)
+github.com/davecgh/go-spew/spew/config.go	 NewDefaultConfig		 100.00% (1/1)
+github.com/davecgh/go-spew/spew/common.go	 printInt			 100.00% (1/1)
+github.com/davecgh/go-spew/spew/common.go	 printUint			 100.00% (1/1)
+github.com/davecgh/go-spew/spew/common.go	 valuesSorter.Len		 100.00% (1/1)
+github.com/davecgh/go-spew/spew/common.go	 valuesSorter.Swap		 100.00% (1/1)
+github.com/davecgh/go-spew/spew/config.go	 ConfigState.Errorf		 100.00% (1/1)
+github.com/davecgh/go-spew/spew/config.go	 ConfigState.Fprint		 100.00% (1/1)
+github.com/davecgh/go-spew/spew/config.go	 ConfigState.Fprintf		 100.00% (1/1)
+github.com/davecgh/go-spew/spew/config.go	 ConfigState.Fprintln		 100.00% (1/1)
+github.com/davecgh/go-spew/spew/config.go	 ConfigState.Print		 100.00% (1/1)
+github.com/davecgh/go-spew/spew/config.go	 ConfigState.Printf		 100.00% (1/1)
+github.com/davecgh/go-spew/spew/config.go	 ConfigState.Println		 100.00% (1/1)
+github.com/davecgh/go-spew/spew/config.go	 ConfigState.Sprint		 100.00% (1/1)
+github.com/davecgh/go-spew/spew/config.go	 ConfigState.Sprintf		 100.00% (1/1)
+github.com/davecgh/go-spew/spew/config.go	 ConfigState.Sprintln		 100.00% (1/1)
+github.com/davecgh/go-spew/spew/config.go	 ConfigState.NewFormatter	 100.00% (1/1)
+github.com/davecgh/go-spew/spew/config.go	 ConfigState.Fdump		 100.00% (1/1)
+github.com/davecgh/go-spew/spew/config.go	 ConfigState.Dump		 100.00% (1/1)
+github.com/davecgh/go-spew/spew/dump.go		 Fdump				 100.00% (1/1)
+github.com/davecgh/go-spew/spew/dump.go		 Dump				 100.00% (1/1)
+github.com/davecgh/go-spew/spew/spew.go		 Fprintln			 100.00% (1/1)
+github.com/davecgh/go-spew/spew/format.go	 NewFormatter			 100.00% (1/1)
+github.com/davecgh/go-spew/spew/spew.go		 Errorf				 100.00% (1/1)
+github.com/davecgh/go-spew/spew/spew.go		 Fprint				 100.00% (1/1)
+github.com/davecgh/go-spew/spew/spew.go		 Fprintf			 100.00% (1/1)
+github.com/davecgh/go-spew/spew/spew.go		 Print				 100.00% (1/1)
+github.com/davecgh/go-spew/spew			 ------------------------------- 100.00% (505/505)
+

+ 1536 - 0
vendor/github.com/docopt/docopt-go/docopt_test.go

@@ -0,0 +1,1536 @@
+/*
+Based of off docopt.py: https://github.com/docopt/docopt
+
+Licensed under terms of MIT license (see LICENSE-MIT)
+Copyright (c) 2013 Keith Batten, kbatten@gmail.com
+*/
+
+package docopt
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"os"
+	"reflect"
+	"regexp"
+	"strings"
+	"testing"
+)
+
+func TestPatternFlat(t *testing.T) {
+	q := patternList{
+		newArgument("N", nil),
+		newOption("-a", "", 0, false),
+		newArgument("M", nil)}
+	p, err := newRequired(
+		newOneOrMore(newArgument("N", nil)),
+		newOption("-a", "", 0, false),
+		newArgument("M", nil)).flat(patternDefault)
+	if reflect.DeepEqual(p, q) != true {
+		t.Error(err)
+	}
+
+	q = patternList{newOptionsShortcut()}
+	p, err = newRequired(
+		newOptional(newOptionsShortcut()),
+		newOptional(newOption("-a", "", 0, false))).flat(patternOptionSSHORTCUT)
+	if reflect.DeepEqual(p, q) != true {
+		t.Error(err)
+	}
+	return
+}
+
+func TestOption(t *testing.T) {
+	if !parseOption("-h").eq(newOption("-h", "", 0, false)) {
+		t.Fail()
+	}
+	if !parseOption("--help").eq(newOption("", "--help", 0, false)) {
+		t.Fail()
+	}
+	if !parseOption("-h --help").eq(newOption("-h", "--help", 0, false)) {
+		t.Fail()
+	}
+	if !parseOption("-h, --help").eq(newOption("-h", "--help", 0, false)) {
+		t.Fail()
+	}
+
+	if !parseOption("-h TOPIC").eq(newOption("-h", "", 1, false)) {
+		t.Fail()
+	}
+	if !parseOption("--help TOPIC").eq(newOption("", "--help", 1, false)) {
+		t.Fail()
+	}
+	if !parseOption("-h TOPIC --help TOPIC").eq(newOption("-h", "--help", 1, false)) {
+		t.Fail()
+	}
+	if !parseOption("-h TOPIC, --help TOPIC").eq(newOption("-h", "--help", 1, false)) {
+		t.Fail()
+	}
+	if !parseOption("-h TOPIC, --help=TOPIC").eq(newOption("-h", "--help", 1, false)) {
+		t.Fail()
+	}
+
+	if !parseOption("-h  Description...").eq(newOption("-h", "", 0, false)) {
+		t.Fail()
+	}
+	if !parseOption("-h --help  Description...").eq(newOption("-h", "--help", 0, false)) {
+		t.Fail()
+	}
+	if !parseOption("-h TOPIC  Description...").eq(newOption("-h", "", 1, false)) {
+		t.Fail()
+	}
+
+	if !parseOption("    -h").eq(newOption("-h", "", 0, false)) {
+		t.Fail()
+	}
+
+	if !parseOption("-h TOPIC  Description... [default: 2]").eq(newOption("-h", "", 1, "2")) {
+		t.Fail()
+	}
+	if !parseOption("-h TOPIC  Descripton... [default: topic-1]").eq(newOption("-h", "", 1, "topic-1")) {
+		t.Fail()
+	}
+	if !parseOption("--help=TOPIC  ... [default: 3.14]").eq(newOption("", "--help", 1, "3.14")) {
+		t.Fail()
+	}
+	if !parseOption("-h, --help=DIR  ... [default: ./]").eq(newOption("-h", "--help", 1, "./")) {
+		t.Fail()
+	}
+	if !parseOption("-h TOPIC  Descripton... [dEfAuLt: 2]").eq(newOption("-h", "", 1, "2")) {
+		t.Fail()
+	}
+	return
+}
+
+func TestOptionName(t *testing.T) {
+	if newOption("-h", "", 0, false).name != "-h" {
+		t.Fail()
+	}
+	if newOption("-h", "--help", 0, false).name != "--help" {
+		t.Fail()
+	}
+	if newOption("", "--help", 0, false).name != "--help" {
+		t.Fail()
+	}
+	return
+}
+
+func TestCommands(t *testing.T) {
+	if v, err := Parse("Usage: prog add", []string{"add"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"add": true}) != true {
+		t.Error(err)
+	}
+	if v, err := Parse("Usage: prog [add]", []string{}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"add": false}) != true {
+		t.Error(err)
+	}
+	if v, err := Parse("Usage: prog [add]", []string{"add"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"add": true}) != true {
+		t.Error(err)
+	}
+	if v, err := Parse("Usage: prog (add|rm)", []string{"add"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"add": true, "rm": false}) != true {
+		t.Error(err)
+	}
+	if v, err := Parse("Usage: prog (add|rm)", []string{"rm"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"add": false, "rm": true}) != true {
+		t.Error(err)
+	}
+	if v, err := Parse("Usage: prog a b", []string{"a", "b"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"a": true, "b": true}) != true {
+		t.Error(err)
+	}
+	_, err := Parse("Usage: prog a b", []string{"b", "a"}, true, "", false, false)
+	if _, ok := err.(*UserError); !ok {
+		t.Error(err)
+	}
+	return
+}
+
+func TestFormalUsage(t *testing.T) {
+	doc := `
+    Usage: prog [-hv] ARG
+           prog N M
+
+    prog is a program`
+	usage := parseSection("usage:", doc)[0]
+	if usage != "Usage: prog [-hv] ARG\n           prog N M" {
+		t.FailNow()
+	}
+	formal, err := formalUsage(usage)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if formal != "( [-hv] ARG ) | ( N M )" {
+		t.Fail()
+	}
+	return
+}
+
+func TestParseArgv(t *testing.T) {
+	o := patternList{
+		newOption("-h", "", 0, false),
+		newOption("-v", "--verbose", 0, false),
+		newOption("-f", "--file", 1, false),
+	}
+
+	p, err := parseArgv(tokenListFromString(""), &o, false)
+	q := patternList{}
+	if reflect.DeepEqual(p, q) != true {
+		t.Error(err)
+	}
+
+	p, err = parseArgv(tokenListFromString("-h"), &o, false)
+	q = patternList{newOption("-h", "", 0, true)}
+	if reflect.DeepEqual(p, q) != true {
+		t.Error(err)
+	}
+
+	p, err = parseArgv(tokenListFromString("-h --verbose"), &o, false)
+	q = patternList{
+		newOption("-h", "", 0, true),
+		newOption("-v", "--verbose", 0, true),
+	}
+	if reflect.DeepEqual(p, q) != true {
+		t.Error(err)
+	}
+
+	p, err = parseArgv(tokenListFromString("-h --file f.txt"), &o, false)
+	q = patternList{
+		newOption("-h", "", 0, true),
+		newOption("-f", "--file", 1, "f.txt"),
+	}
+	if reflect.DeepEqual(p, q) != true {
+		t.Error(err)
+	}
+
+	p, err = parseArgv(tokenListFromString("-h --file f.txt arg"), &o, false)
+	q = patternList{
+		newOption("-h", "", 0, true),
+		newOption("-f", "--file", 1, "f.txt"),
+		newArgument("", "arg"),
+	}
+	if reflect.DeepEqual(p, q) != true {
+		t.Error(err)
+	}
+
+	p, err = parseArgv(tokenListFromString("-h --file f.txt arg arg2"), &o, false)
+	q = patternList{
+		newOption("-h", "", 0, true),
+		newOption("-f", "--file", 1, "f.txt"),
+		newArgument("", "arg"),
+		newArgument("", "arg2"),
+	}
+	if reflect.DeepEqual(p, q) != true {
+		t.Error(err)
+	}
+
+	p, err = parseArgv(tokenListFromString("-h arg -- -v"), &o, false)
+	q = patternList{
+		newOption("-h", "", 0, true),
+		newArgument("", "arg"),
+		newArgument("", "--"),
+		newArgument("", "-v"),
+	}
+	if reflect.DeepEqual(p, q) != true {
+		t.Error(err)
+	}
+}
+
+func TestParsePattern(t *testing.T) {
+	o := patternList{
+		newOption("-h", "", 0, false),
+		newOption("-v", "--verbose", 0, false),
+		newOption("-f", "--file", 1, false),
+	}
+
+	p, err := parsePattern("[ -h ]", &o)
+	q := newRequired(newOptional(newOption("-h", "", 0, false)))
+	if p.eq(q) != true {
+		t.Error(err)
+	}
+
+	p, err = parsePattern("[ ARG ... ]", &o)
+	q = newRequired(newOptional(
+		newOneOrMore(
+			newArgument("ARG", nil))))
+	if p.eq(q) != true {
+		t.Error(err)
+	}
+
+	p, err = parsePattern("[ -h | -v ]", &o)
+	q = newRequired(
+		newOptional(
+			newEither(
+				newOption("-h", "", 0, false),
+				newOption("-v", "--verbose", 0, false))))
+	if p.eq(q) != true {
+		t.Error(err)
+	}
+
+	p, err = parsePattern("( -h | -v [ --file <f> ] )", &o)
+	q = newRequired(
+		newRequired(
+			newEither(
+				newOption("-h", "", 0, false),
+				newRequired(
+					newOption("-v", "--verbose", 0, false),
+					newOptional(
+						newOption("-f", "--file", 1, nil))))))
+	if p.eq(q) != true {
+		t.Error(err)
+	}
+
+	p, err = parsePattern("(-h|-v[--file=<f>]N...)", &o)
+	q = newRequired(
+		newRequired(
+			newEither(
+				newOption("-h", "", 0, false),
+				newRequired(
+					newOption("-v", "--verbose", 0, false),
+					newOptional(
+						newOption("-f", "--file", 1, nil)),
+					newOneOrMore(
+						newArgument("N", nil))))))
+	if p.eq(q) != true {
+		t.Error(err)
+	}
+
+	p, err = parsePattern("(N [M | (K | L)] | O P)", &o)
+	q = newRequired(
+		newRequired(
+			newEither(
+				newRequired(
+					newArgument("N", nil),
+					newOptional(
+						newEither(
+							newArgument("M", nil),
+							newRequired(
+								newEither(
+									newArgument("K", nil),
+									newArgument("L", nil)))))),
+				newRequired(
+					newArgument("O", nil),
+					newArgument("P", nil)))))
+	if p.eq(q) != true {
+		t.Error(err)
+	}
+
+	p, err = parsePattern("[ -h ] [N]", &o)
+	q = newRequired(
+		newOptional(
+			newOption("-h", "", 0, false)),
+		newOptional(
+			newArgument("N", nil)))
+	if p.eq(q) != true {
+		t.Error(err)
+	}
+
+	p, err = parsePattern("[options]", &o)
+	q = newRequired(
+		newOptional(
+			newOptionsShortcut()))
+	if p.eq(q) != true {
+		t.Error(err)
+	}
+
+	p, err = parsePattern("[options] A", &o)
+	q = newRequired(
+		newOptional(
+			newOptionsShortcut()),
+		newArgument("A", nil))
+	if p.eq(q) != true {
+		t.Error(err)
+	}
+
+	p, err = parsePattern("-v [options]", &o)
+	q = newRequired(
+		newOption("-v", "--verbose", 0, false),
+		newOptional(
+			newOptionsShortcut()))
+	if p.eq(q) != true {
+		t.Error(err)
+	}
+
+	p, err = parsePattern("ADD", &o)
+	q = newRequired(newArgument("ADD", nil))
+	if p.eq(q) != true {
+		t.Error(err)
+	}
+
+	p, err = parsePattern("<add>", &o)
+	q = newRequired(newArgument("<add>", nil))
+	if p.eq(q) != true {
+		t.Error(err)
+	}
+
+	p, err = parsePattern("add", &o)
+	q = newRequired(newCommand("add", false))
+	if p.eq(q) != true {
+		t.Error(err)
+	}
+}
+
+func TestOptionMatch(t *testing.T) {
+	v, w, x := newOption("-a", "", 0, false).match(
+		&patternList{newOption("-a", "", 0, true)}, nil)
+	y := patternList{newOption("-a", "", 0, true)}
+	if v != true ||
+		reflect.DeepEqual(*w, patternList{}) != true ||
+		reflect.DeepEqual(*x, y) != true {
+		t.Fail()
+	}
+
+	v, w, x = newOption("-a", "", 0, false).match(
+		&patternList{newOption("-x", "", 0, false)}, nil)
+	y = patternList{newOption("-x", "", 0, false)}
+	if v != false ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, patternList{}) != true {
+		t.Fail()
+	}
+
+	v, w, x = newOption("-a", "", 0, false).match(
+		&patternList{newOption("-x", "", 0, false)}, nil)
+	y = patternList{newOption("-x", "", 0, false)}
+	if v != false ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, patternList{}) != true {
+		t.Fail()
+	}
+	v, w, x = newOption("-a", "", 0, false).match(
+		&patternList{newArgument("N", nil)}, nil)
+	y = patternList{newArgument("N", nil)}
+	if v != false ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, patternList{}) != true {
+		t.Fail()
+	}
+
+	v, w, x = newOption("-a", "", 0, false).match(
+		&patternList{
+			newOption("-x", "", 0, false),
+			newOption("-a", "", 0, false),
+			newArgument("N", nil)}, nil)
+	y = patternList{
+		newOption("-x", "", 0, false),
+		newArgument("N", nil)}
+	z := patternList{newOption("-a", "", 0, false)}
+	if v != true ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, z) != true {
+		t.Fail()
+	}
+
+	v, w, x = newOption("-a", "", 0, false).match(
+		&patternList{
+			newOption("-a", "", 0, true),
+			newOption("-a", "", 0, false)}, nil)
+	y = patternList{newOption("-a", "", 0, false)}
+	z = patternList{newOption("-a", "", 0, true)}
+	if v != true ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, z) != true {
+		t.Fail()
+	}
+}
+
+func TestArgumentMatch(t *testing.T) {
+	v, w, x := newArgument("N", nil).match(
+		&patternList{newArgument("N", 9)}, nil)
+	y := patternList{newArgument("N", 9)}
+	if v != true ||
+		reflect.DeepEqual(*w, patternList{}) != true ||
+		reflect.DeepEqual(*x, y) != true {
+		t.Fail()
+	}
+
+	v, w, x = newArgument("N", nil).match(
+		&patternList{newOption("-x", "", 0, false)}, nil)
+	y = patternList{newOption("-x", "", 0, false)}
+	if v != false ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, patternList{}) != true {
+		t.Fail()
+	}
+
+	v, w, x = newArgument("N", nil).match(
+		&patternList{newOption("-x", "", 0, false),
+			newOption("-a", "", 0, false),
+			newArgument("", 5)}, nil)
+	y = patternList{newOption("-x", "", 0, false),
+		newOption("-a", "", 0, false)}
+	z := patternList{newArgument("N", 5)}
+	if v != true ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, z) != true {
+		t.Fail()
+	}
+
+	v, w, x = newArgument("N", nil).match(
+		&patternList{newArgument("", 9),
+			newArgument("", 0)}, nil)
+	y = patternList{newArgument("", 0)}
+	z = patternList{newArgument("N", 9)}
+	if v != true ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, z) != true {
+		t.Fail()
+	}
+}
+
+func TestCommandMatch(t *testing.T) {
+	v, w, x := newCommand("c", false).match(
+		&patternList{newArgument("", "c")}, nil)
+	y := patternList{newCommand("c", true)}
+	if v != true ||
+		reflect.DeepEqual(*w, patternList{}) != true ||
+		reflect.DeepEqual(*x, y) != true {
+		t.Fail()
+	}
+
+	v, w, x = newCommand("c", false).match(
+		&patternList{newOption("-x", "", 0, false)}, nil)
+	y = patternList{newOption("-x", "", 0, false)}
+	if v != false ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, patternList{}) != true {
+		t.Fail()
+	}
+
+	v, w, x = newCommand("c", false).match(
+		&patternList{
+			newOption("-x", "", 0, false),
+			newOption("-a", "", 0, false),
+			newArgument("", "c")}, nil)
+	y = patternList{newOption("-x", "", 0, false),
+		newOption("-a", "", 0, false)}
+	z := patternList{newCommand("c", true)}
+	if v != true ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, z) != true {
+		t.Fail()
+	}
+
+	v, w, x = newEither(
+		newCommand("add", false),
+		newCommand("rm", false)).match(
+		&patternList{newArgument("", "rm")}, nil)
+	y = patternList{newCommand("rm", true)}
+	if v != true ||
+		reflect.DeepEqual(*w, patternList{}) != true ||
+		reflect.DeepEqual(*x, y) != true {
+		t.Fail()
+	}
+}
+
+func TestOptionalMatch(t *testing.T) {
+	v, w, x := newOptional(newOption("-a", "", 0, false)).match(
+		&patternList{newOption("-a", "", 0, false)}, nil)
+	y := patternList{newOption("-a", "", 0, false)}
+	if v != true ||
+		reflect.DeepEqual(*w, patternList{}) != true ||
+		reflect.DeepEqual(*x, y) != true {
+		t.Fail()
+	}
+
+	v, w, x = newOptional(newOption("-a", "", 0, false)).match(
+		&patternList{}, nil)
+	if v != true ||
+		reflect.DeepEqual(*w, patternList{}) != true ||
+		reflect.DeepEqual(*x, patternList{}) != true {
+		t.Fail()
+	}
+
+	v, w, x = newOptional(newOption("-a", "", 0, false)).match(
+		&patternList{newOption("-x", "", 0, false)}, nil)
+	y = patternList{newOption("-x", "", 0, false)}
+	if v != true ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, patternList{}) != true {
+		t.Fail()
+	}
+
+	v, w, x = newOptional(newOption("-a", "", 0, false),
+		newOption("-b", "", 0, false)).match(
+		&patternList{newOption("-a", "", 0, false)}, nil)
+	y = patternList{newOption("-a", "", 0, false)}
+	if v != true ||
+		reflect.DeepEqual(*w, patternList{}) != true ||
+		reflect.DeepEqual(*x, y) != true {
+		t.Fail()
+	}
+
+	v, w, x = newOptional(newOption("-a", "", 0, false),
+		newOption("-b", "", 0, false)).match(
+		&patternList{newOption("-b", "", 0, false)}, nil)
+	y = patternList{newOption("-b", "", 0, false)}
+	if v != true ||
+		reflect.DeepEqual(*w, patternList{}) != true ||
+		reflect.DeepEqual(*x, y) != true {
+		t.Fail()
+	}
+
+	v, w, x = newOptional(newOption("-a", "", 0, false),
+		newOption("-b", "", 0, false)).match(
+		&patternList{newOption("-x", "", 0, false)}, nil)
+	y = patternList{newOption("-x", "", 0, false)}
+	if v != true ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, patternList{}) != true {
+		t.Fail()
+	}
+
+	v, w, x = newOptional(newArgument("N", nil)).match(
+		&patternList{newArgument("", 9)}, nil)
+	y = patternList{newArgument("N", 9)}
+	if v != true ||
+		reflect.DeepEqual(*w, patternList{}) != true ||
+		reflect.DeepEqual(*x, y) != true {
+		t.Fail()
+	}
+
+	v, w, x = newOptional(newOption("-a", "", 0, false),
+		newOption("-b", "", 0, false)).match(
+		&patternList{newOption("-b", "", 0, false),
+			newOption("-x", "", 0, false),
+			newOption("-a", "", 0, false)}, nil)
+	y = patternList{newOption("-x", "", 0, false)}
+	z := patternList{newOption("-a", "", 0, false),
+		newOption("-b", "", 0, false)}
+	if v != true ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, z) != true {
+		t.Fail()
+	}
+}
+
+func TestRequiredMatch(t *testing.T) {
+	v, w, x := newRequired(newOption("-a", "", 0, false)).match(
+		&patternList{newOption("-a", "", 0, false)}, nil)
+	y := patternList{newOption("-a", "", 0, false)}
+	if v != true ||
+		reflect.DeepEqual(*w, patternList{}) != true ||
+		reflect.DeepEqual(*x, y) != true {
+		t.Fail()
+	}
+
+	v, w, x = newRequired(newOption("-a", "", 0, false)).match(&patternList{}, nil)
+	if v != false ||
+		reflect.DeepEqual(*w, patternList{}) != true ||
+		reflect.DeepEqual(*x, patternList{}) != true {
+		t.Fail()
+	}
+
+	v, w, x = newRequired(newOption("-a", "", 0, false)).match(
+		&patternList{newOption("-x", "", 0, false)}, nil)
+	y = patternList{newOption("-x", "", 0, false)}
+	if v != false ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, patternList{}) != true {
+		t.Fail()
+	}
+	v, w, x = newRequired(newOption("-a", "", 0, false),
+		newOption("-b", "", 0, false)).match(
+		&patternList{newOption("-a", "", 0, false)}, nil)
+	y = patternList{newOption("-a", "", 0, false)}
+	if v != false ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, patternList{}) != true {
+		t.Fail()
+	}
+}
+
+func TestEitherMatch(t *testing.T) {
+	v, w, x := newEither(
+		newOption("-a", "", 0, false),
+		newOption("-b", "", 0, false)).match(
+		&patternList{newOption("-a", "", 0, false)}, nil)
+	y := patternList{newOption("-a", "", 0, false)}
+	if v != true ||
+		reflect.DeepEqual(*w, patternList{}) != true ||
+		reflect.DeepEqual(*x, y) != true {
+		t.Fail()
+	}
+
+	v, w, x = newEither(
+		newOption("-a", "", 0, false),
+		newOption("-b", "", 0, false)).match(&patternList{
+		newOption("-a", "", 0, false),
+		newOption("-b", "", 0, false)}, nil)
+	y = patternList{newOption("-b", "", 0, false)}
+	z := patternList{newOption("-a", "", 0, false)}
+	if v != true ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, z) != true {
+		t.Fail()
+	}
+
+	v, w, x = newEither(
+		newOption("-a", "", 0, false),
+		newOption("-b", "", 0, false)).match(&patternList{
+		newOption("-x", "", 0, false)}, nil)
+	y = patternList{newOption("-x", "", 0, false)}
+	z = patternList{}
+	if v != false ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, z) != true {
+		t.Fail()
+	}
+
+	v, w, x = newEither(
+		newOption("-a", "", 0, false),
+		newOption("-b", "", 0, false),
+		newOption("-c", "", 0, false)).match(&patternList{
+		newOption("-x", "", 0, false),
+		newOption("-b", "", 0, false)}, nil)
+	y = patternList{newOption("-x", "", 0, false)}
+	z = patternList{newOption("-b", "", 0, false)}
+	if v != true ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, z) != true {
+		t.Fail()
+	}
+	v, w, x = newEither(
+		newArgument("M", nil),
+		newRequired(newArgument("N", nil),
+			newArgument("M", nil))).match(&patternList{
+		newArgument("", 1),
+		newArgument("", 2)}, nil)
+	y = patternList{}
+	z = patternList{newArgument("N", 1), newArgument("M", 2)}
+	if v != true ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, z) != true {
+		t.Fail()
+	}
+}
+
+func TestOneOrMoreMatch(t *testing.T) {
+	v, w, x := newOneOrMore(newArgument("N", nil)).match(
+		&patternList{newArgument("", 9)}, nil)
+	y := patternList{newArgument("N", 9)}
+	if v != true ||
+		reflect.DeepEqual(*w, patternList{}) != true ||
+		reflect.DeepEqual(*x, y) != true {
+		t.Fail()
+	}
+
+	v, w, x = newOneOrMore(newArgument("N", nil)).match(
+		&patternList{}, nil)
+	y = patternList{}
+	z := patternList{}
+	if v != false ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, z) != true {
+		t.Fail()
+	}
+
+	v, w, x = newOneOrMore(newArgument("N", nil)).match(
+		&patternList{newOption("-x", "", 0, false)}, nil)
+	y = patternList{newOption("-x", "", 0, false)}
+	z = patternList{}
+	if v != false ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, z) != true {
+		t.Fail()
+	}
+
+	v, w, x = newOneOrMore(newArgument("N", nil)).match(
+		&patternList{newArgument("", 9), newArgument("", 8)}, nil)
+	y = patternList{}
+	z = patternList{newArgument("N", 9), newArgument("N", 8)}
+	if v != true ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, z) != true {
+		t.Fail()
+	}
+
+	v, w, x = newOneOrMore(newArgument("N", nil)).match(&patternList{
+		newArgument("", 9),
+		newOption("-x", "", 0, false),
+		newArgument("", 8)}, nil)
+	y = patternList{newOption("-x", "", 0, false)}
+	z = patternList{newArgument("N", 9), newArgument("N", 8)}
+	if v != true ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, z) != true {
+		t.Fail()
+	}
+
+	v, w, x = newOneOrMore(newOption("-a", "", 0, false)).match(&patternList{
+		newOption("-a", "", 0, false),
+		newArgument("", 8),
+		newOption("-a", "", 0, false)}, nil)
+	y = patternList{newArgument("", 8)}
+	z = patternList{newOption("-a", "", 0, false), newOption("-a", "", 0, false)}
+	if v != true ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, z) != true {
+		t.Fail()
+	}
+
+	v, w, x = newOneOrMore(newOption("-a", "", 0, false)).match(&patternList{
+		newArgument("", 8),
+		newOption("-x", "", 0, false)}, nil)
+	y = patternList{newArgument("", 8), newOption("-x", "", 0, false)}
+	z = patternList{}
+	if v != false ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, z) != true {
+		t.Fail()
+	}
+
+	v, w, x = newOneOrMore(newRequired(newOption("-a", "", 0, false),
+		newArgument("N", nil))).match(&patternList{
+		newOption("-a", "", 0, false),
+		newArgument("", 1),
+		newOption("-x", "", 0, false),
+		newOption("-a", "", 0, false),
+		newArgument("", 2)}, nil)
+	y = patternList{newOption("-x", "", 0, false)}
+	z = patternList{newOption("-a", "", 0, false),
+		newArgument("N", 1),
+		newOption("-a", "", 0, false),
+		newArgument("N", 2)}
+	if v != true ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, z) != true {
+		t.Fail()
+	}
+
+	v, w, x = newOneOrMore(newOptional(newArgument("N", nil))).match(
+		&patternList{newArgument("", 9)}, nil)
+	y = patternList{}
+	z = patternList{newArgument("N", 9)}
+	if v != true ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, z) != true {
+		t.Fail()
+	}
+}
+
+func TestListArgumentMatch(t *testing.T) {
+	p := newRequired(
+		newArgument("N", nil),
+		newArgument("N", nil))
+	p.fix()
+	v, w, x := p.match(&patternList{newArgument("", "1"),
+		newArgument("", "2")}, nil)
+	y := patternList{newArgument("N", []string{"1", "2"})}
+	if v != true ||
+		reflect.DeepEqual(*w, patternList{}) != true ||
+		reflect.DeepEqual(*x, y) != true {
+		t.Fail()
+	}
+
+	p = newOneOrMore(newArgument("N", nil))
+	p.fix()
+	v, w, x = p.match(&patternList{newArgument("", "1"),
+		newArgument("", "2"), newArgument("", "3")}, nil)
+	y = patternList{newArgument("N", []string{"1", "2", "3"})}
+	if v != true ||
+		reflect.DeepEqual(*w, patternList{}) != true ||
+		reflect.DeepEqual(*x, y) != true {
+		t.Fail()
+	}
+
+	p = newRequired(newArgument("N", nil),
+		newOneOrMore(newArgument("N", nil)))
+	p.fix()
+	v, w, x = p.match(&patternList{
+		newArgument("", "1"),
+		newArgument("", "2"),
+		newArgument("", "3")}, nil)
+	y = patternList{newArgument("N", []string{"1", "2", "3"})}
+	if v != true ||
+		reflect.DeepEqual(*w, patternList{}) != true ||
+		reflect.DeepEqual(*x, y) != true {
+		t.Fail()
+	}
+
+	p = newRequired(newArgument("N", nil),
+		newRequired(newArgument("N", nil)))
+	p.fix()
+	v, w, x = p.match(&patternList{
+		newArgument("", "1"),
+		newArgument("", "2")}, nil)
+	y = patternList{newArgument("N", []string{"1", "2"})}
+	if v != true ||
+		reflect.DeepEqual(*w, patternList{}) != true ||
+		reflect.DeepEqual(*x, y) != true {
+		t.Fail()
+	}
+}
+
+func TestBasicPatternMatching(t *testing.T) {
+	// ( -a N [ -x Z ] )
+	p := newRequired(
+		newOption("-a", "", 0, false),
+		newArgument("N", nil),
+		newOptional(
+			newOption("-x", "", 0, false),
+			newArgument("Z", nil)))
+
+	// -a N
+	q := patternList{newOption("-a", "", 0, false), newArgument("", 9)}
+	y := patternList{newOption("-a", "", 0, false), newArgument("N", 9)}
+	v, w, x := p.match(&q, nil)
+	if v != true ||
+		reflect.DeepEqual(*w, patternList{}) != true ||
+		reflect.DeepEqual(*x, y) != true {
+		t.Fail()
+	}
+
+	// -a -x N Z
+	q = patternList{newOption("-a", "", 0, false),
+		newOption("-x", "", 0, false),
+		newArgument("", 9), newArgument("", 5)}
+	y = patternList{}
+	z := patternList{newOption("-a", "", 0, false), newArgument("N", 9),
+		newOption("-x", "", 0, false), newArgument("Z", 5)}
+	v, w, x = p.match(&q, nil)
+	if v != true ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, z) != true {
+		t.Fail()
+	}
+
+	// -x N Z  # BZZ!
+	q = patternList{newOption("-x", "", 0, false),
+		newArgument("", 9), newArgument("", 5)}
+	y = patternList{newOption("-x", "", 0, false),
+		newArgument("", 9), newArgument("", 5)}
+	z = patternList{}
+	v, w, x = p.match(&q, nil)
+	if v != false ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, z) != true {
+		t.Fail()
+	}
+}
+
+func TestPatternEither(t *testing.T) {
+	p := newOption("-a", "", 0, false).transform()
+	q := newEither(newRequired(
+		newOption("-a", "", 0, false)))
+	if p.eq(q) != true {
+		t.Fail()
+	}
+
+	p = newArgument("A", nil).transform()
+	q = newEither(newRequired(
+		newArgument("A", nil)))
+	if p.eq(q) != true {
+		t.Fail()
+	}
+
+	p = newRequired(
+		newEither(
+			newOption("-a", "", 0, false),
+			newOption("-b", "", 0, false)),
+		newOption("-c", "", 0, false)).transform()
+	q = newEither(
+		newRequired(
+			newOption("-a", "", 0, false),
+			newOption("-c", "", 0, false)),
+		newRequired(
+			newOption("-b", "", 0, false),
+			newOption("-c", "", 0, false)))
+	if p.eq(q) != true {
+		t.Fail()
+	}
+
+	p = newOptional(newOption("-a", "", 0, false),
+		newEither(newOption("-b", "", 0, false),
+			newOption("-c", "", 0, false))).transform()
+	q = newEither(
+		newRequired(
+			newOption("-b", "", 0, false), newOption("-a", "", 0, false)),
+		newRequired(
+			newOption("-c", "", 0, false), newOption("-a", "", 0, false)))
+	if p.eq(q) != true {
+		t.Fail()
+	}
+
+	p = newEither(newOption("-x", "", 0, false),
+		newEither(newOption("-y", "", 0, false),
+			newOption("-z", "", 0, false))).transform()
+	q = newEither(
+		newRequired(newOption("-x", "", 0, false)),
+		newRequired(newOption("-y", "", 0, false)),
+		newRequired(newOption("-z", "", 0, false)))
+	if p.eq(q) != true {
+		t.Fail()
+	}
+
+	p = newOneOrMore(newArgument("N", nil),
+		newArgument("M", nil)).transform()
+	q = newEither(
+		newRequired(newArgument("N", nil), newArgument("M", nil),
+			newArgument("N", nil), newArgument("M", nil)))
+	if p.eq(q) != true {
+		t.Fail()
+	}
+}
+
+func TestPatternFixRepeatingArguments(t *testing.T) {
+	p := newOption("-a", "", 0, false)
+	p.fixRepeatingArguments()
+	if p.eq(newOption("-a", "", 0, false)) != true {
+		t.Fail()
+	}
+
+	p = newArgument("N", nil)
+	p.fixRepeatingArguments()
+	if p.eq(newArgument("N", nil)) != true {
+		t.Fail()
+	}
+
+	p = newRequired(
+		newArgument("N", nil),
+		newArgument("N", nil))
+	q := newRequired(
+		newArgument("N", []string{}),
+		newArgument("N", []string{}))
+	p.fixRepeatingArguments()
+	if p.eq(q) != true {
+		t.Fail()
+	}
+
+	p = newEither(
+		newArgument("N", nil),
+		newOneOrMore(newArgument("N", nil)))
+	q = newEither(
+		newArgument("N", []string{}),
+		newOneOrMore(newArgument("N", []string{})))
+	p.fix()
+	if p.eq(q) != true {
+		t.Fail()
+	}
+}
+
+func TestSet(t *testing.T) {
+	p := newArgument("N", nil)
+	q := newArgument("N", nil)
+	if reflect.DeepEqual(p, q) != true {
+		t.Fail()
+	}
+	pl := patternList{newArgument("N", nil), newArgument("N", nil)}
+	ql := patternList{newArgument("N", nil)}
+	if reflect.DeepEqual(pl.unique(), ql.unique()) != true {
+		t.Fail()
+	}
+}
+
+func TestPatternFixIdentities1(t *testing.T) {
+	p := newRequired(
+		newArgument("N", nil),
+		newArgument("N", nil))
+	if len(p.children) < 2 {
+		t.FailNow()
+	}
+	if p.children[0].eq(p.children[1]) != true {
+		t.Fail()
+	}
+	if p.children[0] == p.children[1] {
+		t.Fail()
+	}
+	p.fixIdentities(nil)
+	if p.children[0] != p.children[1] {
+		t.Fail()
+	}
+}
+
+func TestPatternFixIdentities2(t *testing.T) {
+	p := newRequired(
+		newOptional(
+			newArgument("X", nil),
+			newArgument("N", nil)),
+		newArgument("N", nil))
+	if len(p.children) < 2 {
+		t.FailNow()
+	}
+	if len(p.children[0].children) < 2 {
+		t.FailNow()
+	}
+	if p.children[0].children[1].eq(p.children[1]) != true {
+		t.Fail()
+	}
+	if p.children[0].children[1] == p.children[1] {
+		t.Fail()
+	}
+	p.fixIdentities(nil)
+	if p.children[0].children[1] != p.children[1] {
+		t.Fail()
+	}
+}
+
+func TestLongOptionsErrorHandling(t *testing.T) {
+	_, err := Parse("Usage: prog", []string{"--non-existent"}, true, "", false, false)
+	if _, ok := err.(*UserError); !ok {
+		t.Error(fmt.Sprintf("(%s) %s", reflect.TypeOf(err), err))
+	}
+	_, err = Parse("Usage: prog [--version --verbose]\nOptions: --version\n --verbose",
+		[]string{"--ver"}, true, "", false, false)
+	if _, ok := err.(*UserError); !ok {
+		t.Error(err)
+	}
+	_, err = Parse("Usage: prog --long\nOptions: --long ARG", []string{}, true, "", false, false)
+	if _, ok := err.(*LanguageError); !ok {
+		t.Error(err)
+	}
+	_, err = Parse("Usage: prog --long ARG\nOptions: --long ARG",
+		[]string{"--long"}, true, "", false, false)
+	if _, ok := err.(*UserError); !ok {
+		t.Error(fmt.Sprintf("(%s) %s", reflect.TypeOf(err), err))
+	}
+	_, err = Parse("Usage: prog --long=ARG\nOptions: --long", []string{}, true, "", false, false)
+	if _, ok := err.(*LanguageError); !ok {
+		t.Error(err)
+	}
+	_, err = Parse("Usage: prog --long\nOptions: --long",
+		[]string{}, true, "--long=ARG", false, false)
+	if _, ok := err.(*UserError); !ok {
+		t.Error(err)
+	}
+}
+
+func TestShortOptionsErrorHandling(t *testing.T) {
+	_, err := Parse("Usage: prog -x\nOptions: -x  this\n -x  that", []string{}, true, "", false, false)
+	if _, ok := err.(*LanguageError); !ok {
+		t.Error(fmt.Sprintf("(%s) %s", reflect.TypeOf(err), err))
+	}
+	_, err = Parse("Usage: prog", []string{"-x"}, true, "", false, false)
+	if _, ok := err.(*UserError); !ok {
+		t.Error(err)
+	}
+	_, err = Parse("Usage: prog -o\nOptions: -o ARG", []string{}, true, "", false, false)
+	if _, ok := err.(*LanguageError); !ok {
+		t.Error(err)
+	}
+	_, err = Parse("Usage: prog -o ARG\nOptions: -o ARG", []string{"-o"}, true, "", false, false)
+	if _, ok := err.(*UserError); !ok {
+		t.Error(err)
+	}
+}
+
+func TestMatchingParen(t *testing.T) {
+	_, err := Parse("Usage: prog [a [b]", []string{}, true, "", false, false)
+	if _, ok := err.(*LanguageError); !ok {
+		t.Error(err)
+	}
+	_, err = Parse("Usage: prog [a [b] ] c )", []string{}, true, "", false, false)
+	if _, ok := err.(*LanguageError); !ok {
+		t.Error(err)
+	}
+}
+
+func TestAllowDoubleDash(t *testing.T) {
+	if v, err := Parse("usage: prog [-o] [--] <arg>\noptions: -o", []string{"--", "-o"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"-o": false, "<arg>": "-o", "--": true}) != true {
+		t.Error(err)
+	}
+	if v, err := Parse("usage: prog [-o] [--] <arg>\noptions: -o", []string{"-o", "1"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"-o": true, "<arg>": "1", "--": false}) != true {
+		t.Error(err)
+	}
+	_, err := Parse("usage: prog [-o] <arg>\noptions:-o", []string{"-o"}, true, "", false, false)
+	if _, ok := err.(*UserError); !ok { //"--" is not allowed; FIXME?
+		t.Error(err)
+	}
+}
+
+func TestDocopt(t *testing.T) {
+	doc := `Usage: prog [-v] A
+
+                Options: -v  Be verbose.`
+	if v, err := Parse(doc, []string{"arg"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"-v": false, "A": "arg"}) != true {
+		t.Error(err)
+	}
+	if v, err := Parse(doc, []string{"-v", "arg"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"-v": true, "A": "arg"}) != true {
+		t.Error(err)
+	}
+
+	doc = `Usage: prog [-vqr] [FILE]
+              prog INPUT OUTPUT
+              prog --help
+
+    Options:
+      -v  print status messages
+      -q  report only file names
+      -r  show all occurrences of the same error
+      --help
+
+    `
+	if v, err := Parse(doc, []string{"-v", "file.py"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"-v": true, "-q": false, "-r": false, "--help": false, "FILE": "file.py", "INPUT": nil, "OUTPUT": nil}) != true {
+		t.Error(err)
+	}
+	if v, err := Parse(doc, []string{"-v"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"-v": true, "-q": false, "-r": false, "--help": false, "FILE": nil, "INPUT": nil, "OUTPUT": nil}) != true {
+		t.Error(err)
+	}
+
+	_, err := Parse(doc, []string{"-v", "input.py", "output.py"}, true, "", false, false) // does not match
+	if _, ok := err.(*UserError); !ok {
+		t.Error(err)
+	}
+	_, err = Parse(doc, []string{"--fake"}, true, "", false, false)
+	if _, ok := err.(*UserError); !ok {
+		t.Error(err)
+	}
+	_, output, err := parseOutput(doc, []string{"--hel"}, true, "", false)
+	if err != nil || len(output) == 0 {
+		t.Error(err)
+	}
+}
+
+func TestLanguageErrors(t *testing.T) {
+	_, err := Parse("no usage with colon here", []string{}, true, "", false, false)
+	if _, ok := err.(*LanguageError); !ok {
+		t.Error(err)
+	}
+	_, err = Parse("usage: here \n\n and again usage: here", []string{}, true, "", false, false)
+	if _, ok := err.(*LanguageError); !ok {
+		t.Error(err)
+	}
+}
+
+func TestIssue40(t *testing.T) {
+	_, output, err := parseOutput("usage: prog --help-commands | --help", []string{"--help"}, true, "", false)
+	if err != nil || len(output) == 0 {
+		t.Error(err)
+	}
+	if v, err := Parse("usage: prog --aabb | --aa", []string{"--aa"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"--aabb": false, "--aa": true}) != true {
+		t.Error(err)
+	}
+}
+
+func TestIssue34UnicodeStrings(t *testing.T) {
+	// TODO: see if applicable
+}
+
+func TestCountMultipleFlags(t *testing.T) {
+	if v, err := Parse("usage: prog [-v]", []string{"-v"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"-v": true}) != true {
+		t.Error(err)
+	}
+	if v, err := Parse("usage: prog [-vv]", []string{}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"-v": 0}) != true {
+		t.Error(err)
+	}
+	if v, err := Parse("usage: prog [-vv]", []string{"-v"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"-v": 1}) != true {
+		t.Error(err)
+	}
+	if v, err := Parse("usage: prog [-vv]", []string{"-vv"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"-v": 2}) != true {
+		t.Error(err)
+	}
+	_, err := Parse("usage: prog [-vv]", []string{"-vvv"}, true, "", false, false)
+	if _, ok := err.(*UserError); !ok {
+		t.Error(err)
+	}
+	if v, err := Parse("usage: prog [-v | -vv | -vvv]", []string{"-vvv"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"-v": 3}) != true {
+		t.Error(err)
+	}
+	if v, err := Parse("usage: prog [-v...]", []string{"-vvvvvv"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"-v": 6}) != true {
+		t.Error(err)
+	}
+	if v, err := Parse("usage: prog [--ver --ver]", []string{"--ver", "--ver"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"--ver": 2}) != true {
+		t.Error(err)
+	}
+}
+
+func TestAnyOptionsParameter(t *testing.T) {
+	_, err := Parse("usage: prog [options]",
+		[]string{"-foo", "--bar", "--spam=eggs"}, true, "", false, false)
+	if _, ok := err.(*UserError); !ok {
+		t.Fail()
+	}
+
+	_, err = Parse("usage: prog [options]",
+		[]string{"--foo", "--bar", "--bar"}, true, "", false, false)
+	if _, ok := err.(*UserError); !ok {
+		t.Fail()
+	}
+	_, err = Parse("usage: prog [options]",
+		[]string{"--bar", "--bar", "--bar", "-ffff"}, true, "", false, false)
+	if _, ok := err.(*UserError); !ok {
+		t.Fail()
+	}
+	_, err = Parse("usage: prog [options]",
+		[]string{"--long=arg", "--long=another"}, true, "", false, false)
+	if _, ok := err.(*UserError); !ok {
+		t.Fail()
+	}
+}
+
+func TestDefaultValueForPositionalArguments(t *testing.T) {
+	doc := "Usage: prog [--data=<data>...]\nOptions:\n\t-d --data=<arg>    Input data [default: x]"
+	if v, err := Parse(doc, []string{}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"--data": []string{"x"}}) != true {
+		t.Error(err)
+	}
+
+	doc = "Usage: prog [--data=<data>...]\nOptions:\n\t-d --data=<arg>    Input data [default: x y]"
+	if v, err := Parse(doc, []string{}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"--data": []string{"x", "y"}}) != true {
+		t.Error(err)
+	}
+
+	doc = "Usage: prog [--data=<data>...]\nOptions:\n\t-d --data=<arg>    Input data [default: x y]"
+	if v, err := Parse(doc, []string{"--data=this"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"--data": []string{"this"}}) != true {
+		t.Error(err)
+	}
+}
+
+func TestIssue59(t *testing.T) {
+	if v, err := Parse("usage: prog --long=<a>", []string{"--long="}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"--long": ""}) != true {
+		t.Error(err)
+	}
+
+	if v, err := Parse("usage: prog -l <a>\noptions: -l <a>", []string{"-l", ""}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"-l": ""}) != true {
+		t.Error(err)
+	}
+}
+
+func TestOptionsFirst(t *testing.T) {
+	if v, err := Parse("usage: prog [--opt] [<args>...]", []string{"--opt", "this", "that"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"--opt": true, "<args>": []string{"this", "that"}}) != true {
+		t.Error(err)
+	}
+
+	if v, err := Parse("usage: prog [--opt] [<args>...]", []string{"this", "that", "--opt"}, true, "", false, false); reflect.DeepEqual(v, map[string]interface{}{"--opt": true, "<args>": []string{"this", "that"}}) != true {
+		t.Error(err)
+	}
+
+	if v, err := Parse("usage: prog [--opt] [<args>...]", []string{"this", "that", "--opt"}, true, "", true, false); reflect.DeepEqual(v, map[string]interface{}{"--opt": false, "<args>": []string{"this", "that", "--opt"}}) != true {
+		t.Error(err)
+	}
+}
+
+func TestIssue68OptionsShortcutDoesNotIncludeOptionsInUsagePattern(t *testing.T) {
+	args, err := Parse("usage: prog [-ab] [options]\noptions: -x\n -y", []string{"-ax"}, true, "", false, false)
+
+	if args["-a"] != true {
+		t.Error(err)
+	}
+	if args["-b"] != false {
+		t.Error(err)
+	}
+	if args["-x"] != true {
+		t.Error(err)
+	}
+	if args["-y"] != false {
+		t.Error(err)
+	}
+}
+
+func TestIssue65EvaluateArgvWhenCalledNotWhenImported(t *testing.T) {
+	os.Args = strings.Fields("prog -a")
+	v, err := Parse("usage: prog [-ab]", nil, true, "", false, false)
+	w := map[string]interface{}{"-a": true, "-b": false}
+	if reflect.DeepEqual(v, w) != true {
+		t.Error(err)
+	}
+
+	os.Args = strings.Fields("prog -b")
+	v, err = Parse("usage: prog [-ab]", nil, true, "", false, false)
+	w = map[string]interface{}{"-a": false, "-b": true}
+	if reflect.DeepEqual(v, w) != true {
+		t.Error(err)
+	}
+}
+
+func TestIssue71DoubleDashIsNotAValidOptionArgument(t *testing.T) {
+	_, err := Parse("usage: prog [--log=LEVEL] [--] <args>...",
+		[]string{"--log", "--", "1", "2"}, true, "", false, false)
+	if _, ok := err.(*UserError); !ok {
+		t.Fail()
+	}
+
+	_, err = Parse(`usage: prog [-l LEVEL] [--] <args>...
+                  options: -l LEVEL`, []string{"-l", "--", "1", "2"}, true, "", false, false)
+	if _, ok := err.(*UserError); !ok {
+		t.Fail()
+	}
+}
+
+func TestParseSection(t *testing.T) {
+	v := parseSection("usage:", "foo bar fizz buzz")
+	w := []string{}
+	if reflect.DeepEqual(v, w) != true {
+		t.Fail()
+	}
+
+	v = parseSection("usage:", "usage: prog")
+	w = []string{"usage: prog"}
+	if reflect.DeepEqual(v, w) != true {
+		t.Fail()
+	}
+
+	v = parseSection("usage:", "usage: -x\n -y")
+	w = []string{"usage: -x\n -y"}
+	if reflect.DeepEqual(v, w) != true {
+		t.Fail()
+	}
+
+	usage := `usage: this
+
+usage:hai
+usage: this that
+
+usage: foo
+       bar
+
+PROGRAM USAGE:
+ foo
+ bar
+usage:
+` + "\t" + `too
+` + "\t" + `tar
+Usage: eggs spam
+BAZZ
+usage: pit stop`
+
+	v = parseSection("usage:", usage)
+	w = []string{"usage: this",
+		"usage:hai",
+		"usage: this that",
+		"usage: foo\n       bar",
+		"PROGRAM USAGE:\n foo\n bar",
+		"usage:\n\ttoo\n\ttar",
+		"Usage: eggs spam",
+		"usage: pit stop",
+	}
+	if reflect.DeepEqual(v, w) != true {
+		t.Fail()
+	}
+}
+
+func TestIssue126DefaultsNotParsedCorrectlyWhenTabs(t *testing.T) {
+	section := "Options:\n\t--foo=<arg>  [default: bar]"
+	v := patternList{newOption("", "--foo", 1, "bar")}
+	if reflect.DeepEqual(parseDefaults(section), v) != true {
+		t.Fail()
+	}
+}
+
+// conf file based test cases
+func TestFileTestcases(t *testing.T) {
+	filenames := []string{"testcases.docopt", "test_golang.docopt"}
+	for _, filename := range filenames {
+		raw, err := ioutil.ReadFile(filename)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		tests, err := parseTest(raw)
+		if err != nil {
+			t.Fatal(err)
+		}
+		for _, c := range tests {
+			result, err := Parse(c.doc, c.argv, true, "", false, false)
+			if _, ok := err.(*UserError); c.userError && !ok {
+				// expected a user-error
+				t.Error("testcase:", c.id, "result:", result)
+			} else if _, ok := err.(*UserError); !c.userError && ok {
+				// unexpected user-error
+				t.Error("testcase:", c.id, "error:", err, "result:", result)
+			} else if reflect.DeepEqual(c.expect, result) != true {
+				t.Error("testcase:", c.id, "result:", result, "expect:", c.expect)
+			}
+		}
+	}
+}
+
+type testcase struct {
+	id        int
+	doc       string
+	prog      string
+	argv      []string
+	expect    map[string]interface{}
+	userError bool
+}
+
+func parseTest(raw []byte) ([]testcase, error) {
+	var res []testcase
+	commentPattern := regexp.MustCompile("#.*")
+	raw = commentPattern.ReplaceAll(raw, []byte(""))
+	raw = bytes.TrimSpace(raw)
+	if bytes.HasPrefix(raw, []byte(`"""`)) {
+		raw = raw[3:]
+	}
+
+	id := 0
+	for _, fixture := range bytes.Split(raw, []byte(`r"""`)) {
+		doc, _, body := stringPartition(string(fixture), `"""`)
+		for _, cas := range strings.Split(body, "$")[1:] {
+			argvString, _, expectString := stringPartition(strings.TrimSpace(cas), "\n")
+			prog, _, argvString := stringPartition(strings.TrimSpace(argvString), " ")
+			argv := []string{}
+			if len(argvString) > 0 {
+				argv = strings.Fields(argvString)
+			}
+			var expectUntyped interface{}
+			err := json.Unmarshal([]byte(expectString), &expectUntyped)
+			if err != nil {
+				return nil, err
+			}
+			switch expect := expectUntyped.(type) {
+			case string: // user-error
+				res = append(res, testcase{id, doc, prog, argv, nil, true})
+			case map[string]interface{}:
+				// convert []interface{} values to []string
+				// convert float64 values to int
+				for k, vUntyped := range expect {
+					switch v := vUntyped.(type) {
+					case []interface{}:
+						itemList := make([]string, len(v))
+						for i, itemUntyped := range v {
+							if item, ok := itemUntyped.(string); ok {
+								itemList[i] = item
+							}
+						}
+						expect[k] = itemList
+					case float64:
+						expect[k] = int(v)
+					}
+				}
+				res = append(res, testcase{id, doc, prog, argv, expect, false})
+			default:
+				return nil, fmt.Errorf("unhandled json data type")
+			}
+			id++
+		}
+	}
+	return res, nil
+}
+
+// parseOutput wraps the Parse() function to also return stdout
+func parseOutput(doc string, argv []string, help bool, version string,
+	optionsFirst bool) (map[string]interface{}, string, error) {
+	stdout := os.Stdout
+	r, w, _ := os.Pipe()
+	os.Stdout = w
+
+	args, err := Parse(doc, argv, help, version, optionsFirst, false)
+
+	outChan := make(chan string)
+	go func() {
+		var buf bytes.Buffer
+		io.Copy(&buf, r)
+		outChan <- buf.String()
+	}()
+
+	w.Close()
+	os.Stdout = stdout
+	output := <-outChan
+
+	return args, output, err
+}
+
+var debugEnabled = false
+
+func debugOn(l ...interface{}) {
+	debugEnabled = true
+	debug(l...)
+}
+func debugOff(l ...interface{}) {
+	debug(l...)
+	debugEnabled = false
+}
+
+func debug(l ...interface{}) {
+	if debugEnabled {
+		fmt.Println(l...)
+	}
+}

+ 37 - 0
vendor/github.com/docopt/docopt-go/example_test.go

@@ -0,0 +1,37 @@
+package docopt
+
+import (
+	"fmt"
+	"sort"
+)
+
+func ExampleParse() {
+	usage := `Usage:
+  config_example tcp [<host>] [--force] [--timeout=<seconds>]
+  config_example serial <port> [--baud=<rate>] [--timeout=<seconds>]
+  config_example -h | --help | --version`
+	// parse the command line `comfig_example tcp 127.0.0.1 --force`
+	argv := []string{"tcp", "127.0.0.1", "--force"}
+	arguments, _ := Parse(usage, argv, true, "0.1.1rc", false)
+	// sort the keys of the arguments map
+	var keys []string
+	for k := range arguments {
+		keys = append(keys, k)
+	}
+	sort.Strings(keys)
+	// print the argument keys and values
+	for _, k := range keys {
+		fmt.Printf("%9s %v\n", k, arguments[k])
+	}
+	// output:
+	//    --baud <nil>
+	//   --force true
+	//    --help false
+	// --timeout <nil>
+	// --version false
+	//        -h false
+	//    <host> 127.0.0.1
+	//    <port> <nil>
+	//    serial false
+	//       tcp true
+}

+ 29 - 0
vendor/github.com/docopt/docopt-go/examples/arguments/arguments_example.go

@@ -0,0 +1,29 @@
+package main
+
+import (
+	"fmt"
+	"github.com/docopt/docopt-go"
+)
+
+func main() {
+	usage := `Usage: arguments_example [-vqrh] [FILE] ...
+       arguments_example (--left | --right) CORRECTION FILE
+
+Process FILE and optionally apply correction to either left-hand side or
+right-hand side.
+
+Arguments:
+  FILE        optional input file
+  CORRECTION  correction angle, needs FILE, --left or --right to be present
+
+Options:
+  -h --help
+  -v       verbose mode
+  -q       quiet mode
+  -r       make report
+  --left   use left-hand side
+  --right  use right-hand side`
+
+	arguments, _ := docopt.Parse(usage, nil, true, "", false)
+	fmt.Println(arguments)
+}

+ 26 - 0
vendor/github.com/docopt/docopt-go/examples/calculator/calculator_example.go

@@ -0,0 +1,26 @@
+package main
+
+import (
+	"fmt"
+	"github.com/docopt/docopt-go"
+)
+
+func main() {
+	usage := `Not a serious example.
+
+Usage:
+  calculator_example <value> ( ( + | - | * | / ) <value> )...
+  calculator_example <function> <value> [( , <value> )]...
+  calculator_example (-h | --help)
+
+Examples:
+  calculator_example 1 + 2 + 3 + 4 + 5
+  calculator_example 1 + 2 '*' 3 / 4 - 5    # note quotes around '*'
+  calculator_example sum 10 , 20 , 30 , 40
+
+Options:
+  -h, --help
+`
+	arguments, _ := docopt.Parse(usage, nil, true, "", false)
+	fmt.Println(arguments)
+}

+ 76 - 0
vendor/github.com/docopt/docopt-go/examples/config_file/config_file_example.go

@@ -0,0 +1,76 @@
+package main
+
+import (
+	"encoding/json"
+	"fmt"
+	"github.com/docopt/docopt-go"
+	"strings"
+)
+
+func loadJSONConfig() map[string]interface{} {
+	var result map[string]interface{}
+	jsonData := []byte(`{"--force": true, "--timeout": "10", "--baud": "9600"}`)
+	json.Unmarshal(jsonData, &result)
+	return result
+}
+
+func loadIniConfig() map[string]interface{} {
+	iniData := `
+[default-arguments]
+--force
+--baud=19200
+<host>=localhost`
+	// trivial ini parser
+	// default value for an item is bool: true (for --force)
+	// otherwise the value is a string
+	iniParsed := make(map[string]map[string]interface{})
+	var section string
+	for _, line := range strings.Split(iniData, "\n") {
+		if strings.HasPrefix(line, "[") {
+			section = line
+			iniParsed[section] = make(map[string]interface{})
+		} else if section != "" {
+			kv := strings.SplitN(line, "=", 2)
+			if len(kv) == 1 {
+				iniParsed[section][kv[0]] = true
+			} else if len(kv) == 2 {
+				iniParsed[section][kv[0]] = kv[1]
+			}
+		}
+	}
+	return iniParsed["[default-arguments]"]
+}
+
+// merge combines two maps.
+// truthiness takes priority over falsiness
+// mapA takes priority over mapB
+func merge(mapA, mapB map[string]interface{}) map[string]interface{} {
+	result := make(map[string]interface{})
+	for k, v := range mapA {
+		result[k] = v
+	}
+	for k, v := range mapB {
+		if _, ok := result[k]; !ok || result[k] == nil || result[k] == false {
+			result[k] = v
+		}
+	}
+	return result
+}
+
+func main() {
+	usage := `Usage:
+  config_file_example tcp [<host>] [--force] [--timeout=<seconds>]
+  config_file_example serial <port> [--baud=<rate>] [--timeout=<seconds>]
+  config_file_example -h | --help | --version`
+
+	jsonConfig := loadJSONConfig()
+	iniConfig := loadIniConfig()
+	arguments, _ := docopt.Parse(usage, nil, true, "0.1.1rc", false)
+
+	// Arguments take priority over INI, INI takes priority over JSON
+	result := merge(arguments, merge(iniConfig, jsonConfig))
+
+	fmt.Println("JSON config: ", jsonConfig)
+	fmt.Println("INI config: ", iniConfig)
+	fmt.Println("Result: ", result)
+}

+ 22 - 0
vendor/github.com/docopt/docopt-go/examples/counted/counted_example.go

@@ -0,0 +1,22 @@
+package main
+
+import (
+	"fmt"
+	"github.com/docopt/docopt-go"
+)
+
+func main() {
+	usage := `Usage: counted_example --help
+       counted_example -v...
+       counted_example go [go]
+       counted_example (--path=<path>)...
+       counted_example <file> <file>
+
+Try: counted_example -vvvvvvvvvv
+     counted_example go go
+     counted_example --path ./here --path ./there
+     counted_example this.txt that.txt`
+
+	arguments, _ := docopt.Parse(usage, nil, true, "", false)
+	fmt.Println(arguments)
+}

+ 38 - 0
vendor/github.com/docopt/docopt-go/examples/git/branch/git_branch.go

@@ -0,0 +1,38 @@
+package git
+
+import (
+	"fmt"
+	"github.com/docopt/docopt-go"
+)
+
+func main() {
+	usage := `usage: git branch [options] [-r | -a] [--merged=<commit> | --no-merged=<commit>]
+       git branch [options] [-l] [-f] <branchname> [<start-point>]
+       git branch [options] [-r] (-d | -D) <branchname>
+       git branch [options] (-m | -M) [<oldbranch>] <newbranch>
+
+Generic options:
+    -h, --help
+    -v, --verbose         show hash and subject, give twice for upstream branch
+    -t, --track           set up tracking mode (see git-pull(1))
+    --set-upstream        change upstream info
+    --color=<when>        use colored output
+    -r                    act on remote-tracking branches
+    --contains=<commit>   print only branches that contain the commit
+    --abbrev=<n>          use <n> digits to display SHA-1s
+
+Specific git-branch actions:
+    -a                    list both remote-tracking and local branches
+    -d                    delete fully merged branch
+    -D                    delete branch (even if not merged)
+    -m                    move/rename a branch and its reflog
+    -M                    move/rename a branch, even if target exists
+    -l                    create the branch's reflog
+    -f, --force           force creation (when already exists)
+    --no-merged=<commit>  print only not merged branches
+    --merged=<commit>     print only merged branches
+`
+
+	args, _ := docopt.Parse(usage, nil, true, "", false)
+	fmt.Println(args)
+}

+ 30 - 0
vendor/github.com/docopt/docopt-go/examples/git/checkout/git_checkout.go

@@ -0,0 +1,30 @@
+package git
+
+import (
+	"fmt"
+	"github.com/docopt/docopt-go"
+)
+
+func main() {
+	usage := `usage: git checkout [options] <branch>
+       git checkout [options] <branch> -- <file>...
+
+options:
+    -q, --quiet           suppress progress reporting
+    -b <branch>           create and checkout a new branch
+    -B <branch>           create/reset and checkout a branch
+    -l                    create reflog for new branch
+    -t, --track           set upstream info for new branch
+    --orphan <new branch>
+                          new unparented branch
+    -2, --ours            checkout our version for unmerged files
+    -3, --theirs          checkout their version for unmerged files
+    -f, --force           force checkout (throw away local modifications)
+    -m, --merge           perform a 3-way merge with the new branch
+    --conflict <style>    conflict style (merge or diff3)
+    -p, --patch           select hunks interactively
+`
+
+	args, _ := docopt.Parse(usage, nil, true, "", false)
+	fmt.Println(args)
+}

+ 37 - 0
vendor/github.com/docopt/docopt-go/examples/git/clone/git_clone.go

@@ -0,0 +1,37 @@
+package git
+
+import (
+	"fmt"
+	"github.com/docopt/docopt-go"
+)
+
+func main() {
+	usage := `usage: git clone [options] [--] <repo> [<dir>]
+
+options:
+    -v, --verbose         be more verbose
+    -q, --quiet           be more quiet
+    --progress            force progress reporting
+    -n, --no-checkout     don't create a checkout
+    --bare                create a bare repository
+    --mirror              create a mirror repository (implies bare)
+    -l, --local           to clone from a local repository
+    --no-hardlinks        don't use local hardlinks, always copy
+    -s, --shared          setup as shared repository
+    --recursive           initialize submodules in the clone
+    --recurse-submodules  initialize submodules in the clone
+    --template <template-directory>
+                          directory from which templates will be used
+    --reference <repo>    reference repository
+    -o, --origin <branch>
+                          use <branch> instead of 'origin' to track upstream
+    -b, --branch <branch>
+                          checkout <branch> instead of the remote's HEAD
+    -u, --upload-pack <path>
+                          path to git-upload-pack on the remote
+    --depth <depth>       create a shallow clone of that depth
+`
+
+	args, _ := docopt.Parse(usage, nil, true, "", false)
+	fmt.Println(args)
+}

+ 108 - 0
vendor/github.com/docopt/docopt-go/examples/git/git.go

@@ -0,0 +1,108 @@
+package main
+
+import (
+	"fmt"
+	"github.com/docopt/docopt-go"
+	"os"
+	"os/exec"
+)
+
+func main() {
+	usage := `usage: git [--version] [--exec-path=<path>] [--html-path]
+           [-p|--paginate|--no-pager] [--no-replace-objects]
+           [--bare] [--git-dir=<path>] [--work-tree=<path>]
+           [-c <name>=<value>] [--help]
+           <command> [<args>...]
+
+options:
+   -c <name=value>
+   -h, --help
+   -p, --paginate
+
+The most commonly used git commands are:
+   add        Add file contents to the index
+   branch     List, create, or delete branches
+   checkout   Checkout a branch or paths to the working tree
+   clone      Clone a repository into a new directory
+   commit     Record changes to the repository
+   push       Update remote refs along with associated objects
+   remote     Manage set of tracked repositories
+
+See 'git help <command>' for more information on a specific command.
+`
+	args, _ := docopt.Parse(usage, nil, true, "git version 1.7.4.4", true)
+
+	fmt.Println("global arguments:")
+	fmt.Println(args)
+
+	fmt.Println("command arguments:")
+	cmd := args["<command>"].(string)
+	cmdArgs := args["<args>"].([]string)
+
+	err := runCommand(cmd, cmdArgs)
+	if err != nil {
+		fmt.Println(err)
+		os.Exit(1)
+	}
+}
+
+func goRun(scriptName string, args []string) (err error) {
+	cmdArgs := make([]string, 2)
+	cmdArgs[0] = "run"
+	cmdArgs[1] = scriptName
+	cmdArgs = append(cmdArgs, args...)
+	osCmd := exec.Command("go", cmdArgs...)
+	var out []byte
+	out, err = osCmd.Output()
+	fmt.Println(string(out))
+	if err != nil {
+		return
+	}
+	return
+}
+
+func runCommand(cmd string, args []string) (err error) {
+	argv := make([]string, 1)
+	argv[0] = cmd
+	argv = append(argv, args...)
+	switch cmd {
+	case "add":
+		// subcommand is a function call
+		return cmdAdd(argv)
+	case "branch":
+		// subcommand is a script
+		return goRun("branch/git_branch.go", argv)
+	case "checkout", "clone", "commit", "push", "remote":
+		// subcommand is a script
+		scriptName := fmt.Sprintf("%s/git_%s.go", cmd, cmd)
+		return goRun(scriptName, argv)
+	case "help", "":
+		return goRun("git.go", []string{"git_add.go", "--help"})
+	}
+
+	return fmt.Errorf("%s is not a git command. See 'git help'", cmd)
+}
+
+func cmdAdd(argv []string) (err error) {
+	usage := `usage: git add [options] [--] [<filepattern>...]
+
+options:
+	-h, --help
+	-n, --dry-run        dry run
+	-v, --verbose        be verbose
+	-i, --interactive    interactive picking
+	-p, --patch          select hunks interactively
+	-e, --edit           edit current diff and apply
+	-f, --force          allow adding otherwise ignored files
+	-u, --update         update tracked files
+	-N, --intent-to-add  record only the fact that the path will be added later
+	-A, --all            add all, noticing removal of tracked files
+	--refresh            don't add, only refresh the index
+	--ignore-errors      just skip files which cannot be added because of errors
+	--ignore-missing     check if - even missing - files are ignored in dry run
+`
+
+	args, _ := docopt.Parse(usage, nil, true, "", false)
+	fmt.Println(args)
+	return
+}

+ 34 - 0
vendor/github.com/docopt/docopt-go/examples/git/push/git_push.go

@@ -0,0 +1,34 @@
+package git
+
+import (
+	"fmt"
+	"github.com/docopt/docopt-go"
+)
+
+func main() {
+	usage := `usage: git push [options] [<repository> [<refspec>...]]
+
+options:
+    -h, --help
+    -v, --verbose         be more verbose
+    -q, --quiet           be more quiet
+    --repo <repository>   repository
+    --all                 push all refs
+    --mirror              mirror all refs
+    --delete              delete refs
+    --tags                push tags (can't be used with --all or --mirror)
+    -n, --dry-run         dry run
+    --porcelain           machine-readable output
+    -f, --force           force updates
+    --thin                use thin pack
+    --receive-pack <receive-pack>
+                          receive pack program
+    --exec <receive-pack>
+                          receive pack program
+    -u, --set-upstream    set upstream for git pull/status
+    --progress            force progress reporting
+`
+
+	args, _ := docopt.Parse(usage, nil, true, "", false)
+	fmt.Println(args)
+}

+ 28 - 0
vendor/github.com/docopt/docopt-go/examples/git/remote/git_remote.go

@@ -0,0 +1,28 @@
+package git
+
+import (
+	"fmt"
+	"github.com/docopt/docopt-go"
+)
+
+func main() {
+	usage := `usage: git remote [-v | --verbose]
+       git remote add [-t <branch>] [-m <master>] [-f] [--mirror] <name> <url>
+       git remote rename <old> <new>
+       git remote rm <name>
+       git remote set-head <name> (-a | -d | <branch>)
+       git remote [-v | --verbose] show [-n] <name>
+       git remote prune [-n | --dry-run] <name>
+       git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]
+       git remote set-branches <name> [--add] <branch>...
+       git remote set-url <name> <newurl> [<oldurl>]
+       git remote set-url --add <name> <newurl>
+       git remote set-url --delete <name> <url>
+
+options:
+    -v, --verbose         be verbose; must be placed before a subcommand
+`
+
+	args, _ := docopt.Parse(usage, nil, true, "", false)
+	fmt.Println(args)
+}

+ 28 - 0
vendor/github.com/docopt/docopt-go/examples/naval_fate/naval_fate.go

@@ -0,0 +1,28 @@
+package main
+
+import (
+	"fmt"
+	"github.com/docopt/docopt-go"
+)
+
+func main() {
+	usage := `Naval Fate.
+
+Usage:
+  naval_fate ship new <name>...
+  naval_fate ship <name> move <x> <y> [--speed=<kn>]
+  naval_fate ship shoot <x> <y>
+  naval_fate mine (set|remove) <x> <y> [--moored|--drifting]
+  naval_fate -h | --help
+  naval_fate --version
+
+Options:
+  -h --help     Show this screen.
+  --version     Show version.
+  --speed=<kn>  Speed in knots [default: 10].
+  --moored      Moored (anchored) mine.
+  --drifting    Drifting mine.`
+
+	arguments, _ := docopt.Parse(usage, nil, true, "Naval Fate 2.0", false)
+	fmt.Println(arguments)
+}

+ 19 - 0
vendor/github.com/docopt/docopt-go/examples/odd_even/odd_even_example.go

@@ -0,0 +1,19 @@
+package main
+
+import (
+	"fmt"
+	"github.com/docopt/docopt-go"
+)
+
+func main() {
+	usage := `Usage: odd_even_example [-h | --help] (ODD EVEN)...
+
+Example, try:
+  odd_even_example 1 2 3 4
+
+Options:
+  -h, --help`
+
+	arguments, _ := docopt.Parse(usage, nil, true, "", false)
+	fmt.Println(arguments)
+}

+ 43 - 0
vendor/github.com/docopt/docopt-go/examples/options/options_example.go

@@ -0,0 +1,43 @@
+package main
+
+import (
+	"fmt"
+	"github.com/docopt/docopt-go"
+)
+
+func main() {
+	usage := `Example of program with many options using docopt.
+
+Usage:
+  options_example [-hvqrf NAME] [--exclude=PATTERNS]
+                     [--select=ERRORS | --ignore=ERRORS] [--show-source]
+                     [--statistics] [--count] [--benchmark] PATH...
+  options_example (--doctest | --testsuite=DIR)
+  options_example --version
+
+Arguments:
+  PATH  destination path
+
+Options:
+  -h --help            show this help message and exit
+  --version            show version and exit
+  -v --verbose         print status messages
+  -q --quiet           report only file names
+  -r --repeat          show all occurrences of the same error
+  --exclude=PATTERNS   exclude files or directories which match these comma
+                       separated patterns [default: .svn,CVS,.bzr,.hg,.git]
+  -f NAME --file=NAME  when parsing directories, only check filenames matching
+                       these comma separated patterns [default: *.go]
+  --select=ERRORS      select errors and warnings (e.g. E,W6)
+  --ignore=ERRORS      skip errors and warnings (e.g. E4,W)
+  --show-source        show source code for each error
+  --statistics         count errors and warnings
+  --count              print total number of errors and warnings to standard
+                       error and set exit code to 1 if total is not null
+  --benchmark          measure processing speed
+  --testsuite=DIR      run regression tests from dir
+  --doctest            run doctest on myself`
+
+	arguments, _ := docopt.Parse(usage, nil, true, "1.0.0rc2", false)
+	fmt.Println(arguments)
+}

+ 24 - 0
vendor/github.com/docopt/docopt-go/examples/options_shortcut/options_shortcut_example.go

@@ -0,0 +1,24 @@
+package main
+
+import (
+	"fmt"
+	"github.com/docopt/docopt-go"
+)
+
+func main() {
+	usage := `Example of program which uses [options] shortcut in pattern.
+
+Usage:
+  options_shortcut_example [options] <port>
+
+Options:
+  -h --help                show this help message and exit
+  --version                show version and exit
+  -n, --number N           use N as a number
+  -t, --timeout TIMEOUT    set timeout TIMEOUT seconds
+  --apply                  apply changes to database
+  -q                       operate in quiet mode`
+
+	arguments, _ := docopt.Parse(usage, nil, true, "1.0.0rc2", false)
+	fmt.Println(arguments)
+}

+ 16 - 0
vendor/github.com/docopt/docopt-go/examples/quick/quick_example.go

@@ -0,0 +1,16 @@
+package main
+
+import (
+	"fmt"
+	"github.com/docopt/docopt-go"
+)
+
+func main() {
+	usage := `Usage:
+  quick_example tcp <host> <port> [--timeout=<seconds>]
+  quick_example serial <port> [--baud=9600] [--timeout=<seconds>]
+  quick_example -h | --help | --version`
+
+	arguments, _ := docopt.Parse(usage, nil, true, "0.1.1rc", false)
+	fmt.Println(arguments)
+}

+ 31 - 0
vendor/github.com/docopt/docopt-go/examples/type_assert/type_assert_example.go

@@ -0,0 +1,31 @@
+package main
+
+import (
+	"fmt"
+	"github.com/docopt/docopt-go"
+)
+
+func main() {
+	usage := `usage: foo [-x] [-y]`
+
+	arguments, err := docopt.Parse(usage, nil, true, "", false)
+	if err != nil {
+		fmt.Println(err)
+	}
+
+	fmt.Println(arguments)
+
+	var x = arguments["-x"].(bool) // type assertion required
+	if x == true {
+		fmt.Println("x is true")
+	}
+
+	y := arguments["-y"] // no type assertion needed
+	if y == true {
+		fmt.Println("y is true")
+	}
+	y2 := arguments["-y"]
+	if y2 == 10 { // this will never be true, a type assertion would have produced a build error
+		fmt.Println("y is 10")
+	}
+}

+ 17 - 0
vendor/github.com/fatedier/beego/.github/ISSUE_TEMPLATE

@@ -0,0 +1,17 @@
+Please answer these questions before submitting your issue. Thanks!
+
+1. What version of Go and beego are you using (`bee version`)?
+
+
+2. What operating system and processor architecture are you using (`go env`)?
+
+
+3. What did you do?
+If possible, provide a recipe for reproducing the error.
+A complete runnable program is good.
+
+
+4. What did you expect to see?
+
+
+5. What did you see instead?

+ 6 - 0
vendor/github.com/fatedier/beego/.gitignore

@@ -0,0 +1,6 @@
+.idea
+.vscode
+.DS_Store
+*.swp
+*.swo
+beego.iml

+ 51 - 0
vendor/github.com/fatedier/beego/.travis.yml

@@ -0,0 +1,51 @@
+language: go
+
+go:
+  - 1.6
+  - 1.5.3
+  - 1.4.3
+services:
+  - redis-server
+  - mysql
+  - postgresql
+  - memcached
+env:
+  - ORM_DRIVER=sqlite3   ORM_SOURCE=$TRAVIS_BUILD_DIR/orm_test.db
+  - ORM_DRIVER=mysql    ORM_SOURCE="root:@/orm_test?charset=utf8"
+  - ORM_DRIVER=postgres ORM_SOURCE="user=postgres dbname=orm_test sslmode=disable"
+before_install:
+ - git clone git://github.com/ideawu/ssdb.git
+ - cd ssdb
+ - make
+ - cd ..
+install:
+  - go get github.com/lib/pq
+  - go get github.com/go-sql-driver/mysql
+  - go get github.com/mattn/go-sqlite3
+  - go get github.com/bradfitz/gomemcache/memcache
+  - go get github.com/garyburd/redigo/redis
+  - go get github.com/beego/x2j
+  - go get github.com/couchbase/go-couchbase
+  - go get github.com/beego/goyaml2
+  - go get github.com/belogik/goes
+  - go get github.com/siddontang/ledisdb/config
+  - go get github.com/siddontang/ledisdb/ledis
+  - go get github.com/ssdb/gossdb/ssdb
+  - go get github.com/cloudflare/golz4
+  - go get github.com/gogo/protobuf/proto
+before_script:
+  - psql --version
+  - sh -c "if [ '$ORM_DRIVER' = 'postgres' ]; then psql -c 'create database orm_test;' -U postgres; fi"
+  - sh -c "if [ '$ORM_DRIVER' = 'mysql' ]; then mysql -u root -e 'create database orm_test;'; fi"
+  - sh -c "if [ '$ORM_DRIVER' = 'sqlite' ]; then touch $TRAVIS_BUILD_DIR/orm_test.db; fi"
+  - sh -c "if [ $(go version) == *1.[5-9]* ]; then go get github.com/golang/lint/golint; golint ./...; fi"
+  - sh -c "if [ $(go version) == *1.[5-9]* ]; then go tool vet .; fi"
+  - mkdir -p res/var
+  - ./ssdb/ssdb-server ./ssdb/ssdb.conf -d
+after_script:
+  -killall -w ssdb-server
+  - rm -rf ./res/var/*
+script:
+  - go test -v ./...
+addons:
+  postgresql: "9.4"

+ 52 - 0
vendor/github.com/fatedier/beego/CONTRIBUTING.md

@@ -0,0 +1,52 @@
+# Contributing to beego
+
+beego is an open source project.
+
+It is the work of hundreds of contributors. We appreciate your help!
+
+Here are instructions to get you started. They are probably not perfect, 
+please let us know if anything feels wrong or incomplete.
+
+## Contribution guidelines
+
+### Pull requests
+
+First of all. beego follow the gitflow. So please send you pull request 
+to **develop** branch. We will close the pull request to master branch.
+
+We are always happy to receive pull requests, and do our best to
+review them as fast as possible. Not sure if that typo is worth a pull
+request? Do it! We will appreciate it.
+
+If your pull request is not accepted on the first try, don't be
+discouraged! Sometimes we can make a mistake, please do more explaining 
+for us. We will appreciate it.
+
+We're trying very hard to keep beego simple and fast. We don't want it
+to do everything for everybody. This means that we might decide against
+incorporating a new feature. But we will give you some advice on how to 
+do it in other way.
+
+### Create issues
+
+Any significant improvement should be documented as [a GitHub
+issue](https://github.com/astaxie/beego/issues) before anybody
+starts working on it. 
+
+Also when filing an issue, make sure to answer these five questions:
+
+- What version of beego are you using (bee version)?
+- What operating system and processor architecture are you using?
+- What did you do?
+- What did you expect to see?
+- What did you see instead?
+
+### but check existing issues and docs first!
+
+Please take a moment to check that an issue doesn't already exist
+documenting your bug report or improvement proposal. If it does, it
+never hurts to add a quick "+1" or "I have this problem too". This will
+help prioritize the most common problems and requests.
+
+Also if you don't know how to use it. please make sure you have read though
+the docs in http://beego.me/docs

+ 62 - 0
vendor/github.com/fatedier/beego/README.md

@@ -0,0 +1,62 @@
+## Beego
+
+[![Build Status](https://travis-ci.org/astaxie/beego.svg?branch=master)](https://travis-ci.org/astaxie/beego)
+[![GoDoc](http://godoc.org/github.com/astaxie/beego?status.svg)](http://godoc.org/github.com/astaxie/beego)
+[![Foundation](https://img.shields.io/badge/Golang-Foundation-green.svg)](http://golangfoundation.org)
+
+beego is used for rapid development of RESTful APIs, web apps and backend services in Go.
+It is inspired by Tornado, Sinatra and Flask. beego has some Go-specific features such as interfaces and struct embedding.
+
+More info [beego.me](http://beego.me)
+
+##Quick Start
+######Download and install
+
+    go get github.com/astaxie/beego
+
+######Create file `hello.go`
+```go
+package main
+
+import "github.com/astaxie/beego"
+
+func main(){
+    beego.Run()
+}
+```
+######Build and run
+```bash
+    go build hello.go
+    ./hello
+```
+######Congratulations! 
+You just built your first beego app.
+Open your browser and visit `http://localhost:8080`.
+Please see [Documentation](http://beego.me/docs) for more.
+
+## Features
+
+* RESTful support
+* MVC architecture
+* Modularity
+* Auto API documents
+* Annotation router
+* Namespace
+* Powerful development tools
+* Full stack for Web & API
+
+## Documentation
+
+* [English](http://beego.me/docs/intro/)
+* [中文文档](http://beego.me/docs/intro/)
+* [Русский](http://beego.me/docs/intro/)
+
+## Community
+
+* [http://beego.me/community](http://beego.me/community)
+* Welcome to join us in Slack: [https://beego.slack.com](https://beego.slack.com), you can get invited from [here](https://github.com/beego/beedoc/issues/232)
+
+## LICENSE
+
+beego source code is licensed under the Apache Licence, Version 2.0
+(http://www.apache.org/licenses/LICENSE-2.0.html).

+ 401 - 0
vendor/github.com/fatedier/beego/admin.go

@@ -0,0 +1,401 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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 beego
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"net/http"
+	"os"
+	"text/template"
+	"time"
+
+	"reflect"
+
+	"github.com/astaxie/beego/grace"
+	"github.com/astaxie/beego/logs"
+	"github.com/astaxie/beego/toolbox"
+	"github.com/astaxie/beego/utils"
+)
+
+// BeeAdminApp is the default adminApp used by admin module.
+var beeAdminApp *adminApp
+
+// FilterMonitorFunc is default monitor filter when admin module is enable.
+// if this func returns, admin module records qbs for this request by condition of this function logic.
+// usage:
+// 	func MyFilterMonitor(method, requestPath string, t time.Duration) bool {
+//	 	if method == "POST" {
+//			return false
+//	 	}
+//	 	if t.Nanoseconds() < 100 {
+//			return false
+//	 	}
+//	 	if strings.HasPrefix(requestPath, "/astaxie") {
+//			return false
+//	 	}
+//	 	return true
+// 	}
+// 	beego.FilterMonitorFunc = MyFilterMonitor.
+var FilterMonitorFunc func(string, string, time.Duration) bool
+
+func init() {
+	beeAdminApp = &adminApp{
+		routers: make(map[string]http.HandlerFunc),
+	}
+	beeAdminApp.Route("/", adminIndex)
+	beeAdminApp.Route("/qps", qpsIndex)
+	beeAdminApp.Route("/prof", profIndex)
+	beeAdminApp.Route("/healthcheck", healthcheck)
+	beeAdminApp.Route("/task", taskStatus)
+	beeAdminApp.Route("/listconf", listConf)
+	FilterMonitorFunc = func(string, string, time.Duration) bool { return true }
+}
+
+// AdminIndex is the default http.Handler for admin module.
+// it matches url pattern "/".
+func adminIndex(rw http.ResponseWriter, r *http.Request) {
+	execTpl(rw, map[interface{}]interface{}{}, indexTpl, defaultScriptsTpl)
+}
+
+// QpsIndex is the http.Handler for writing qbs statistics map result info in http.ResponseWriter.
+// it's registered with url pattern "/qbs" in admin module.
+func qpsIndex(rw http.ResponseWriter, r *http.Request) {
+	data := make(map[interface{}]interface{})
+	data["Content"] = toolbox.StatisticsMap.GetMap()
+	execTpl(rw, data, qpsTpl, defaultScriptsTpl)
+}
+
+// ListConf is the http.Handler of displaying all beego configuration values as key/value pair.
+// it's registered with url pattern "/listconf" in admin module.
+func listConf(rw http.ResponseWriter, r *http.Request) {
+	r.ParseForm()
+	command := r.Form.Get("command")
+	if command == "" {
+		rw.Write([]byte("command not support"))
+		return
+	}
+
+	data := make(map[interface{}]interface{})
+	switch command {
+	case "conf":
+		m := make(map[string]interface{})
+		list("BConfig", BConfig, m)
+		m["AppConfigPath"] = appConfigPath
+		m["AppConfigProvider"] = appConfigProvider
+		tmpl := template.Must(template.New("dashboard").Parse(dashboardTpl))
+		tmpl = template.Must(tmpl.Parse(configTpl))
+		tmpl = template.Must(tmpl.Parse(defaultScriptsTpl))
+
+		data["Content"] = m
+
+		tmpl.Execute(rw, data)
+
+	case "router":
+		var (
+			content = map[string]interface{}{
+				"Fields": []string{
+					"Router Pattern",
+					"Methods",
+					"Controller",
+				},
+			}
+			methods     = []string{}
+			methodsData = make(map[string]interface{})
+		)
+		for method, t := range BeeApp.Handlers.routers {
+
+			resultList := new([][]string)
+
+			printTree(resultList, t)
+
+			methods = append(methods, method)
+			methodsData[method] = resultList
+		}
+
+		content["Data"] = methodsData
+		content["Methods"] = methods
+		data["Content"] = content
+		data["Title"] = "Routers"
+		execTpl(rw, data, routerAndFilterTpl, defaultScriptsTpl)
+	case "filter":
+		var (
+			content = map[string]interface{}{
+				"Fields": []string{
+					"Router Pattern",
+					"Filter Function",
+				},
+			}
+			filterTypes    = []string{}
+			filterTypeData = make(map[string]interface{})
+		)
+
+		if BeeApp.Handlers.enableFilter {
+			var filterType string
+			for k, fr := range map[int]string{
+				BeforeStatic: "Before Static",
+				BeforeRouter: "Before Router",
+				BeforeExec:   "Before Exec",
+				AfterExec:    "After Exec",
+				FinishRouter: "Finish Router"} {
+				if bf := BeeApp.Handlers.filters[k]; len(bf) > 0 {
+					filterType = fr
+					filterTypes = append(filterTypes, filterType)
+					resultList := new([][]string)
+					for _, f := range bf {
+						var result = []string{
+							fmt.Sprintf("%s", f.pattern),
+							fmt.Sprintf("%s", utils.GetFuncName(f.filterFunc)),
+						}
+						*resultList = append(*resultList, result)
+					}
+					filterTypeData[filterType] = resultList
+				}
+			}
+		}
+
+		content["Data"] = filterTypeData
+		content["Methods"] = filterTypes
+
+		data["Content"] = content
+		data["Title"] = "Filters"
+		execTpl(rw, data, routerAndFilterTpl, defaultScriptsTpl)
+	default:
+		rw.Write([]byte("command not support"))
+	}
+}
+
+func list(root string, p interface{}, m map[string]interface{}) {
+	pt := reflect.TypeOf(p)
+	pv := reflect.ValueOf(p)
+	if pt.Kind() == reflect.Ptr {
+		pt = pt.Elem()
+		pv = pv.Elem()
+	}
+	for i := 0; i < pv.NumField(); i++ {
+		var key string
+		if root == "" {
+			key = pt.Field(i).Name
+		} else {
+			key = root + "." + pt.Field(i).Name
+		}
+		if pv.Field(i).Kind() == reflect.Struct {
+			list(key, pv.Field(i).Interface(), m)
+		} else {
+			m[key] = pv.Field(i).Interface()
+		}
+	}
+}
+
+func printTree(resultList *[][]string, t *Tree) {
+	for _, tr := range t.fixrouters {
+		printTree(resultList, tr)
+	}
+	if t.wildcard != nil {
+		printTree(resultList, t.wildcard)
+	}
+	for _, l := range t.leaves {
+		if v, ok := l.runObject.(*controllerInfo); ok {
+			if v.routerType == routerTypeBeego {
+				var result = []string{
+					v.pattern,
+					fmt.Sprintf("%s", v.methods),
+					fmt.Sprintf("%s", v.controllerType),
+				}
+				*resultList = append(*resultList, result)
+			} else if v.routerType == routerTypeRESTFul {
+				var result = []string{
+					v.pattern,
+					fmt.Sprintf("%s", v.methods),
+					"",
+				}
+				*resultList = append(*resultList, result)
+			} else if v.routerType == routerTypeHandler {
+				var result = []string{
+					v.pattern,
+					"",
+					"",
+				}
+				*resultList = append(*resultList, result)
+			}
+		}
+	}
+}
+
+// ProfIndex is a http.Handler for showing profile command.
+// it's in url pattern "/prof" in admin module.
+func profIndex(rw http.ResponseWriter, r *http.Request) {
+	r.ParseForm()
+	command := r.Form.Get("command")
+	if command == "" {
+		return
+	}
+
+	var (
+		format = r.Form.Get("format")
+		data   = make(map[interface{}]interface{})
+		result bytes.Buffer
+	)
+	toolbox.ProcessInput(command, &result)
+	data["Content"] = result.String()
+
+	if format == "json" && command == "gc summary" {
+		dataJSON, err := json.Marshal(data)
+		if err != nil {
+			http.Error(rw, err.Error(), http.StatusInternalServerError)
+			return
+		}
+
+		rw.Header().Set("Content-Type", "application/json")
+		rw.Write(dataJSON)
+		return
+	}
+
+	data["Title"] = command
+	defaultTpl := defaultScriptsTpl
+	if command == "gc summary" {
+		defaultTpl = gcAjaxTpl
+	}
+	execTpl(rw, data, profillingTpl, defaultTpl)
+}
+
+// Healthcheck is a http.Handler calling health checking and showing the result.
+// it's in "/healthcheck" pattern in admin module.
+func healthcheck(rw http.ResponseWriter, req *http.Request) {
+	var (
+		data       = make(map[interface{}]interface{})
+		result     = []string{}
+		resultList = new([][]string)
+		content    = map[string]interface{}{
+			"Fields": []string{"Name", "Message", "Status"},
+		}
+	)
+
+	for name, h := range toolbox.AdminCheckList {
+		if err := h.Check(); err != nil {
+			result = []string{
+				fmt.Sprintf("error"),
+				fmt.Sprintf("%s", name),
+				fmt.Sprintf("%s", err.Error()),
+			}
+
+		} else {
+			result = []string{
+				fmt.Sprintf("success"),
+				fmt.Sprintf("%s", name),
+				fmt.Sprintf("OK"),
+			}
+
+		}
+		*resultList = append(*resultList, result)
+	}
+	content["Data"] = resultList
+	data["Content"] = content
+	data["Title"] = "Health Check"
+	execTpl(rw, data, healthCheckTpl, defaultScriptsTpl)
+}
+
+// TaskStatus is a http.Handler with running task status (task name, status and the last execution).
+// it's in "/task" pattern in admin module.
+func taskStatus(rw http.ResponseWriter, req *http.Request) {
+	data := make(map[interface{}]interface{})
+
+	// Run Task
+	req.ParseForm()
+	taskname := req.Form.Get("taskname")
+	if taskname != "" {
+		if t, ok := toolbox.AdminTaskList[taskname]; ok {
+			if err := t.Run(); err != nil {
+				data["Message"] = []string{"error", fmt.Sprintf("%s", err)}
+			}
+			data["Message"] = []string{"success", fmt.Sprintf("%s run success,Now the Status is <br>%s", taskname, t.GetStatus())}
+		} else {
+			data["Message"] = []string{"warning", fmt.Sprintf("there's no task which named: %s", taskname)}
+		}
+	}
+
+	// List Tasks
+	content := make(map[string]interface{})
+	resultList := new([][]string)
+	var result = []string{}
+	var fields = []string{
+		"Task Name",
+		"Task Spec",
+		"Task Status",
+		"Last Time",
+		"",
+	}
+	for tname, tk := range toolbox.AdminTaskList {
+		result = []string{
+			tname,
+			fmt.Sprintf("%s", tk.GetSpec()),
+			fmt.Sprintf("%s", tk.GetStatus()),
+			tk.GetPrev().String(),
+		}
+		*resultList = append(*resultList, result)
+	}
+
+	content["Fields"] = fields
+	content["Data"] = resultList
+	data["Content"] = content
+	data["Title"] = "Tasks"
+	execTpl(rw, data, tasksTpl, defaultScriptsTpl)
+}
+
+func execTpl(rw http.ResponseWriter, data map[interface{}]interface{}, tpls ...string) {
+	tmpl := template.Must(template.New("dashboard").Parse(dashboardTpl))
+	for _, tpl := range tpls {
+		tmpl = template.Must(tmpl.Parse(tpl))
+	}
+	tmpl.Execute(rw, data)
+}
+
+// adminApp is an http.HandlerFunc map used as beeAdminApp.
+type adminApp struct {
+	routers map[string]http.HandlerFunc
+}
+
+// Route adds http.HandlerFunc to adminApp with url pattern.
+func (admin *adminApp) Route(pattern string, f http.HandlerFunc) {
+	admin.routers[pattern] = f
+}
+
+// Run adminApp http server.
+// Its addr is defined in configuration file as adminhttpaddr and adminhttpport.
+func (admin *adminApp) Run() {
+	if len(toolbox.AdminTaskList) > 0 {
+		toolbox.StartTask()
+	}
+	addr := BConfig.Listen.AdminAddr
+
+	if BConfig.Listen.AdminPort != 0 {
+		addr = fmt.Sprintf("%s:%d", BConfig.Listen.AdminAddr, BConfig.Listen.AdminPort)
+	}
+	for p, f := range admin.routers {
+		http.Handle(p, f)
+	}
+	logs.Info("Admin server Running on %s", addr)
+
+	var err error
+	if BConfig.Listen.Graceful {
+		err = grace.ListenAndServe(addr, nil)
+	} else {
+		err = http.ListenAndServe(addr, nil)
+	}
+	if err != nil {
+		logs.Critical("Admin ListenAndServe: ", err, fmt.Sprintf("%d", os.Getpid()))
+	}
+}

+ 73 - 0
vendor/github.com/fatedier/beego/admin_test.go

@@ -0,0 +1,73 @@
+package beego
+
+import (
+	"fmt"
+	"testing"
+)
+
+func TestList_01(t *testing.T) {
+	m := make(map[string]interface{})
+	list("BConfig", BConfig, m)
+	t.Log(m)
+	om := oldMap()
+	for k, v := range om {
+		if fmt.Sprint(m[k]) != fmt.Sprint(v) {
+			t.Log(k, "old-key", v, "new-key", m[k])
+			t.FailNow()
+		}
+	}
+}
+
+func oldMap() map[string]interface{} {
+	m := make(map[string]interface{})
+	m["BConfig.AppName"] = BConfig.AppName
+	m["BConfig.RunMode"] = BConfig.RunMode
+	m["BConfig.RouterCaseSensitive"] = BConfig.RouterCaseSensitive
+	m["BConfig.ServerName"] = BConfig.ServerName
+	m["BConfig.RecoverPanic"] = BConfig.RecoverPanic
+	m["BConfig.CopyRequestBody"] = BConfig.CopyRequestBody
+	m["BConfig.EnableGzip"] = BConfig.EnableGzip
+	m["BConfig.MaxMemory"] = BConfig.MaxMemory
+	m["BConfig.EnableErrorsShow"] = BConfig.EnableErrorsShow
+	m["BConfig.Listen.Graceful"] = BConfig.Listen.Graceful
+	m["BConfig.Listen.ServerTimeOut"] = BConfig.Listen.ServerTimeOut
+	m["BConfig.Listen.ListenTCP4"] = BConfig.Listen.ListenTCP4
+	m["BConfig.Listen.EnableHTTP"] = BConfig.Listen.EnableHTTP
+	m["BConfig.Listen.HTTPAddr"] = BConfig.Listen.HTTPAddr
+	m["BConfig.Listen.HTTPPort"] = BConfig.Listen.HTTPPort
+	m["BConfig.Listen.EnableHTTPS"] = BConfig.Listen.EnableHTTPS
+	m["BConfig.Listen.HTTPSAddr"] = BConfig.Listen.HTTPSAddr
+	m["BConfig.Listen.HTTPSPort"] = BConfig.Listen.HTTPSPort
+	m["BConfig.Listen.HTTPSCertFile"] = BConfig.Listen.HTTPSCertFile
+	m["BConfig.Listen.HTTPSKeyFile"] = BConfig.Listen.HTTPSKeyFile
+	m["BConfig.Listen.EnableAdmin"] = BConfig.Listen.EnableAdmin
+	m["BConfig.Listen.AdminAddr"] = BConfig.Listen.AdminAddr
+	m["BConfig.Listen.AdminPort"] = BConfig.Listen.AdminPort
+	m["BConfig.Listen.EnableFcgi"] = BConfig.Listen.EnableFcgi
+	m["BConfig.Listen.EnableStdIo"] = BConfig.Listen.EnableStdIo
+	m["BConfig.WebConfig.AutoRender"] = BConfig.WebConfig.AutoRender
+	m["BConfig.WebConfig.EnableDocs"] = BConfig.WebConfig.EnableDocs
+	m["BConfig.WebConfig.FlashName"] = BConfig.WebConfig.FlashName
+	m["BConfig.WebConfig.FlashSeparator"] = BConfig.WebConfig.FlashSeparator
+	m["BConfig.WebConfig.DirectoryIndex"] = BConfig.WebConfig.DirectoryIndex
+	m["BConfig.WebConfig.StaticDir"] = BConfig.WebConfig.StaticDir
+	m["BConfig.WebConfig.StaticExtensionsToGzip"] = BConfig.WebConfig.StaticExtensionsToGzip
+	m["BConfig.WebConfig.TemplateLeft"] = BConfig.WebConfig.TemplateLeft
+	m["BConfig.WebConfig.TemplateRight"] = BConfig.WebConfig.TemplateRight
+	m["BConfig.WebConfig.ViewsPath"] = BConfig.WebConfig.ViewsPath
+	m["BConfig.WebConfig.EnableXSRF"] = BConfig.WebConfig.EnableXSRF
+	m["BConfig.WebConfig.XSRFExpire"] = BConfig.WebConfig.XSRFExpire
+	m["BConfig.WebConfig.Session.SessionOn"] = BConfig.WebConfig.Session.SessionOn
+	m["BConfig.WebConfig.Session.SessionProvider"] = BConfig.WebConfig.Session.SessionProvider
+	m["BConfig.WebConfig.Session.SessionName"] = BConfig.WebConfig.Session.SessionName
+	m["BConfig.WebConfig.Session.SessionGCMaxLifetime"] = BConfig.WebConfig.Session.SessionGCMaxLifetime
+	m["BConfig.WebConfig.Session.SessionProviderConfig"] = BConfig.WebConfig.Session.SessionProviderConfig
+	m["BConfig.WebConfig.Session.SessionCookieLifeTime"] = BConfig.WebConfig.Session.SessionCookieLifeTime
+	m["BConfig.WebConfig.Session.SessionAutoSetCookie"] = BConfig.WebConfig.Session.SessionAutoSetCookie
+	m["BConfig.WebConfig.Session.SessionDomain"] = BConfig.WebConfig.Session.SessionDomain
+	m["BConfig.WebConfig.Session.SessionDisableHTTPOnly"] = BConfig.WebConfig.Session.SessionDisableHTTPOnly
+	m["BConfig.Log.AccessLogs"] = BConfig.Log.AccessLogs
+	m["BConfig.Log.FileLineNum"] = BConfig.Log.FileLineNum
+	m["BConfig.Log.Outputs"] = BConfig.Log.Outputs
+	return m
+}

File diff suppressed because it is too large
+ 286 - 0
vendor/github.com/fatedier/beego/adminui.go


+ 366 - 0
vendor/github.com/fatedier/beego/app.go

@@ -0,0 +1,366 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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 beego
+
+import (
+	"fmt"
+	"net"
+	"net/http"
+	"net/http/fcgi"
+	"os"
+	"path"
+	"time"
+
+	"github.com/astaxie/beego/grace"
+	"github.com/astaxie/beego/logs"
+	"github.com/astaxie/beego/utils"
+)
+
+var (
+	// BeeApp is an application instance
+	BeeApp *App
+)
+
+func init() {
+	// create beego application
+	BeeApp = NewApp()
+}
+
+// App defines beego application with a new PatternServeMux.
+type App struct {
+	Handlers *ControllerRegister
+	Server   *http.Server
+}
+
+// NewApp returns a new beego application.
+func NewApp() *App {
+	cr := NewControllerRegister()
+	app := &App{Handlers: cr, Server: &http.Server{}}
+	return app
+}
+
+// Run beego application.
+func (app *App) Run() {
+	addr := BConfig.Listen.HTTPAddr
+
+	if BConfig.Listen.HTTPPort != 0 {
+		addr = fmt.Sprintf("%s:%d", BConfig.Listen.HTTPAddr, BConfig.Listen.HTTPPort)
+	}
+
+	var (
+		err        error
+		l          net.Listener
+		endRunning = make(chan bool, 1)
+	)
+
+	// run cgi server
+	if BConfig.Listen.EnableFcgi {
+		if BConfig.Listen.EnableStdIo {
+			if err = fcgi.Serve(nil, app.Handlers); err == nil { // standard I/O
+				logs.Info("Use FCGI via standard I/O")
+			} else {
+				logs.Critical("Cannot use FCGI via standard I/O", err)
+			}
+			return
+		}
+		if BConfig.Listen.HTTPPort == 0 {
+			// remove the Socket file before start
+			if utils.FileExists(addr) {
+				os.Remove(addr)
+			}
+			l, err = net.Listen("unix", addr)
+		} else {
+			l, err = net.Listen("tcp", addr)
+		}
+		if err != nil {
+			logs.Critical("Listen: ", err)
+		}
+		if err = fcgi.Serve(l, app.Handlers); err != nil {
+			logs.Critical("fcgi.Serve: ", err)
+		}
+		return
+	}
+
+	app.Server.Handler = app.Handlers
+	app.Server.ReadTimeout = time.Duration(BConfig.Listen.ServerTimeOut) * time.Second
+	app.Server.WriteTimeout = time.Duration(BConfig.Listen.ServerTimeOut) * time.Second
+	app.Server.ErrorLog = logs.GetLogger("HTTP")
+
+	// run graceful mode
+	if BConfig.Listen.Graceful {
+		httpsAddr := BConfig.Listen.HTTPSAddr
+		app.Server.Addr = httpsAddr
+		if BConfig.Listen.EnableHTTPS {
+			go func() {
+				time.Sleep(20 * time.Microsecond)
+				if BConfig.Listen.HTTPSPort != 0 {
+					httpsAddr = fmt.Sprintf("%s:%d", BConfig.Listen.HTTPSAddr, BConfig.Listen.HTTPSPort)
+					app.Server.Addr = httpsAddr
+				}
+				server := grace.NewServer(httpsAddr, app.Handlers)
+				server.Server.ReadTimeout = app.Server.ReadTimeout
+				server.Server.WriteTimeout = app.Server.WriteTimeout
+				if err := server.ListenAndServeTLS(BConfig.Listen.HTTPSCertFile, BConfig.Listen.HTTPSKeyFile); err != nil {
+					logs.Critical("ListenAndServeTLS: ", err, fmt.Sprintf("%d", os.Getpid()))
+					time.Sleep(100 * time.Microsecond)
+					endRunning <- true
+				}
+			}()
+		}
+		if BConfig.Listen.EnableHTTP {
+			go func() {
+				server := grace.NewServer(addr, app.Handlers)
+				server.Server.ReadTimeout = app.Server.ReadTimeout
+				server.Server.WriteTimeout = app.Server.WriteTimeout
+				if BConfig.Listen.ListenTCP4 {
+					server.Network = "tcp4"
+				}
+				if err := server.ListenAndServe(); err != nil {
+					logs.Critical("ListenAndServe: ", err, fmt.Sprintf("%d", os.Getpid()))
+					time.Sleep(100 * time.Microsecond)
+					endRunning <- true
+				}
+			}()
+		}
+		<-endRunning
+		return
+	}
+
+	// run normal mode
+	if BConfig.Listen.EnableHTTPS {
+		go func() {
+			time.Sleep(20 * time.Microsecond)
+			if BConfig.Listen.HTTPSPort != 0 {
+				app.Server.Addr = fmt.Sprintf("%s:%d", BConfig.Listen.HTTPSAddr, BConfig.Listen.HTTPSPort)
+			} else if BConfig.Listen.EnableHTTP {
+				BeeLogger.Info("Start https server error, confict with http.Please reset https port")
+				return
+			}
+			logs.Info("https server Running on https://%s", app.Server.Addr)
+			if err := app.Server.ListenAndServeTLS(BConfig.Listen.HTTPSCertFile, BConfig.Listen.HTTPSKeyFile); err != nil {
+				logs.Critical("ListenAndServeTLS: ", err)
+				time.Sleep(100 * time.Microsecond)
+				endRunning <- true
+			}
+		}()
+	}
+	if BConfig.Listen.EnableHTTP {
+		go func() {
+			app.Server.Addr = addr
+			logs.Info("http server Running on http://%s", app.Server.Addr)
+			if BConfig.Listen.ListenTCP4 {
+				ln, err := net.Listen("tcp4", app.Server.Addr)
+				if err != nil {
+					logs.Critical("ListenAndServe: ", err)
+					time.Sleep(100 * time.Microsecond)
+					endRunning <- true
+					return
+				}
+				if err = app.Server.Serve(ln); err != nil {
+					logs.Critical("ListenAndServe: ", err)
+					time.Sleep(100 * time.Microsecond)
+					endRunning <- true
+					return
+				}
+			} else {
+				if err := app.Server.ListenAndServe(); err != nil {
+					logs.Critical("ListenAndServe: ", err)
+					time.Sleep(100 * time.Microsecond)
+					endRunning <- true
+				}
+			}
+		}()
+	}
+	<-endRunning
+}
+
+// Router adds a patterned controller handler to BeeApp.
+// it's an alias method of App.Router.
+// usage:
+//  simple router
+//  beego.Router("/admin", &admin.UserController{})
+//  beego.Router("/admin/index", &admin.ArticleController{})
+//
+//  regex router
+//
+//  beego.Router("/api/:id([0-9]+)", &controllers.RController{})
+//
+//  custom rules
+//  beego.Router("/api/list",&RestController{},"*:ListFood")
+//  beego.Router("/api/create",&RestController{},"post:CreateFood")
+//  beego.Router("/api/update",&RestController{},"put:UpdateFood")
+//  beego.Router("/api/delete",&RestController{},"delete:DeleteFood")
+func Router(rootpath string, c ControllerInterface, mappingMethods ...string) *App {
+	BeeApp.Handlers.Add(rootpath, c, mappingMethods...)
+	return BeeApp
+}
+
+// Include will generate router file in the router/xxx.go from the controller's comments
+// usage:
+// beego.Include(&BankAccount{}, &OrderController{},&RefundController{},&ReceiptController{})
+// type BankAccount struct{
+//   beego.Controller
+// }
+//
+// register the function
+// func (b *BankAccount)Mapping(){
+//  b.Mapping("ShowAccount" , b.ShowAccount)
+//  b.Mapping("ModifyAccount", b.ModifyAccount)
+//}
+//
+// //@router /account/:id  [get]
+// func (b *BankAccount) ShowAccount(){
+//    //logic
+// }
+//
+//
+// //@router /account/:id  [post]
+// func (b *BankAccount) ModifyAccount(){
+//    //logic
+// }
+//
+// the comments @router url methodlist
+// url support all the function Router's pattern
+// methodlist [get post head put delete options *]
+func Include(cList ...ControllerInterface) *App {
+	BeeApp.Handlers.Include(cList...)
+	return BeeApp
+}
+
+// RESTRouter adds a restful controller handler to BeeApp.
+// its' controller implements beego.ControllerInterface and
+// defines a param "pattern/:objectId" to visit each resource.
+func RESTRouter(rootpath string, c ControllerInterface) *App {
+	Router(rootpath, c)
+	Router(path.Join(rootpath, ":objectId"), c)
+	return BeeApp
+}
+
+// AutoRouter adds defined controller handler to BeeApp.
+// it's same to App.AutoRouter.
+// if beego.AddAuto(&MainContorlller{}) and MainController has methods List and Page,
+// visit the url /main/list to exec List function or /main/page to exec Page function.
+func AutoRouter(c ControllerInterface) *App {
+	BeeApp.Handlers.AddAuto(c)
+	return BeeApp
+}
+
+// AutoPrefix adds controller handler to BeeApp with prefix.
+// it's same to App.AutoRouterWithPrefix.
+// if beego.AutoPrefix("/admin",&MainContorlller{}) and MainController has methods List and Page,
+// visit the url /admin/main/list to exec List function or /admin/main/page to exec Page function.
+func AutoPrefix(prefix string, c ControllerInterface) *App {
+	BeeApp.Handlers.AddAutoPrefix(prefix, c)
+	return BeeApp
+}
+
+// Get used to register router for Get method
+// usage:
+//    beego.Get("/", func(ctx *context.Context){
+//          ctx.Output.Body("hello world")
+//    })
+func Get(rootpath string, f FilterFunc) *App {
+	BeeApp.Handlers.Get(rootpath, f)
+	return BeeApp
+}
+
+// Post used to register router for Post method
+// usage:
+//    beego.Post("/api", func(ctx *context.Context){
+//          ctx.Output.Body("hello world")
+//    })
+func Post(rootpath string, f FilterFunc) *App {
+	BeeApp.Handlers.Post(rootpath, f)
+	return BeeApp
+}
+
+// Delete used to register router for Delete method
+// usage:
+//    beego.Delete("/api", func(ctx *context.Context){
+//          ctx.Output.Body("hello world")
+//    })
+func Delete(rootpath string, f FilterFunc) *App {
+	BeeApp.Handlers.Delete(rootpath, f)
+	return BeeApp
+}
+
+// Put used to register router for Put method
+// usage:
+//    beego.Put("/api", func(ctx *context.Context){
+//          ctx.Output.Body("hello world")
+//    })
+func Put(rootpath string, f FilterFunc) *App {
+	BeeApp.Handlers.Put(rootpath, f)
+	return BeeApp
+}
+
+// Head used to register router for Head method
+// usage:
+//    beego.Head("/api", func(ctx *context.Context){
+//          ctx.Output.Body("hello world")
+//    })
+func Head(rootpath string, f FilterFunc) *App {
+	BeeApp.Handlers.Head(rootpath, f)
+	return BeeApp
+}
+
+// Options used to register router for Options method
+// usage:
+//    beego.Options("/api", func(ctx *context.Context){
+//          ctx.Output.Body("hello world")
+//    })
+func Options(rootpath string, f FilterFunc) *App {
+	BeeApp.Handlers.Options(rootpath, f)
+	return BeeApp
+}
+
+// Patch used to register router for Patch method
+// usage:
+//    beego.Patch("/api", func(ctx *context.Context){
+//          ctx.Output.Body("hello world")
+//    })
+func Patch(rootpath string, f FilterFunc) *App {
+	BeeApp.Handlers.Patch(rootpath, f)
+	return BeeApp
+}
+
+// Any used to register router for all methods
+// usage:
+//    beego.Any("/api", func(ctx *context.Context){
+//          ctx.Output.Body("hello world")
+//    })
+func Any(rootpath string, f FilterFunc) *App {
+	BeeApp.Handlers.Any(rootpath, f)
+	return BeeApp
+}
+
+// Handler used to register a Handler router
+// usage:
+//    beego.Handler("/api", func(ctx *context.Context){
+//          ctx.Output.Body("hello world")
+//    })
+func Handler(rootpath string, h http.Handler, options ...interface{}) *App {
+	BeeApp.Handlers.Handler(rootpath, h, options...)
+	return BeeApp
+}
+
+// InsertFilter adds a FilterFunc with pattern condition and action constant.
+// The pos means action constant including
+// beego.BeforeStatic, beego.BeforeRouter, beego.BeforeExec, beego.AfterExec and beego.FinishRouter.
+// The bool params is for setting the returnOnOutput value (false allows multiple filters to execute)
+func InsertFilter(pattern string, pos int, filter FilterFunc, params ...bool) *App {
+	BeeApp.Handlers.InsertFilter(pattern, pos, filter, params...)
+	return BeeApp
+}

+ 100 - 0
vendor/github.com/fatedier/beego/beego.go

@@ -0,0 +1,100 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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 beego
+
+import (
+	"os"
+	"path/filepath"
+	"strconv"
+	"strings"
+)
+
+const (
+	// VERSION represent beego web framework version.
+	VERSION = "1.8.0"
+
+	// DEV is for develop
+	DEV = "dev"
+	// PROD is for production
+	PROD = "prod"
+)
+
+//hook function to run
+type hookfunc func() error
+
+var (
+	hooks = make([]hookfunc, 0) //hook function slice to store the hookfunc
+)
+
+// AddAPPStartHook is used to register the hookfunc
+// The hookfuncs will run in beego.Run()
+// such as sessionInit, middlerware start, buildtemplate, admin start
+func AddAPPStartHook(hf hookfunc) {
+	hooks = append(hooks, hf)
+}
+
+// Run beego application.
+// beego.Run() default run on HttpPort
+// beego.Run("localhost")
+// beego.Run(":8089")
+// beego.Run("127.0.0.1:8089")
+func Run(params ...string) {
+
+	initBeforeHTTPRun()
+
+	if len(params) > 0 && params[0] != "" {
+		strs := strings.Split(params[0], ":")
+		if len(strs) > 0 && strs[0] != "" {
+			BConfig.Listen.HTTPAddr = strs[0]
+		}
+		if len(strs) > 1 && strs[1] != "" {
+			BConfig.Listen.HTTPPort, _ = strconv.Atoi(strs[1])
+		}
+	}
+
+	BeeApp.Run()
+}
+
+func initBeforeHTTPRun() {
+	//init hooks
+	AddAPPStartHook(registerMime)
+	AddAPPStartHook(registerDefaultErrorHandler)
+	AddAPPStartHook(registerSession)
+	AddAPPStartHook(registerTemplate)
+	AddAPPStartHook(registerAdmin)
+	AddAPPStartHook(registerGzip)
+
+	for _, hk := range hooks {
+		if err := hk(); err != nil {
+			panic(err)
+		}
+	}
+}
+
+// TestBeegoInit is for test package init
+func TestBeegoInit(ap string) {
+	path := filepath.Join(ap, "conf", "app.conf")
+	os.Chdir(ap)
+	InitBeegoBeforeTest(path)
+}
+
+// InitBeegoBeforeTest is for test package init
+func InitBeegoBeforeTest(appConfigPath string) {
+	if err := LoadAppConfig(appConfigProvider, appConfigPath); err != nil {
+		panic(err)
+	}
+	BConfig.RunMode = "test"
+	initBeforeHTTPRun()
+}

+ 59 - 0
vendor/github.com/fatedier/beego/cache/README.md

@@ -0,0 +1,59 @@
+## cache
+cache is a Go cache manager. It can use many cache adapters. The repo is inspired by `database/sql` .
+
+
+## How to install?
+
+	go get github.com/astaxie/beego/cache
+
+
+## What adapters are supported?
+
+As of now this cache support memory, Memcache and Redis.
+
+
+## How to use it?
+
+First you must import it
+
+	import (
+		"github.com/astaxie/beego/cache"
+	)
+
+Then init a Cache (example with memory adapter)
+
+	bm, err := cache.NewCache("memory", `{"interval":60}`)	
+
+Use it like this:	
+	
+	bm.Put("astaxie", 1, 10 * time.Second)
+	bm.Get("astaxie")
+	bm.IsExist("astaxie")
+	bm.Delete("astaxie")
+
+
+## Memory adapter
+
+Configure memory adapter like this:
+
+	{"interval":60}
+
+interval means the gc time. The cache will check at each time interval, whether item has expired.
+
+
+## Memcache adapter
+
+Memcache adapter use the [gomemcache](http://github.com/bradfitz/gomemcache) client.
+
+Configure like this:
+
+	{"conn":"127.0.0.1:11211"}
+
+
+## Redis adapter
+
+Redis adapter use the [redigo](http://github.com/garyburd/redigo) client.
+
+Configure like this:
+
+	{"conn":":6039"}

+ 103 - 0
vendor/github.com/fatedier/beego/cache/cache.go

@@ -0,0 +1,103 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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 provide a Cache interface and some implemetn engine
+// Usage:
+//
+// import(
+//   "github.com/astaxie/beego/cache"
+// )
+//
+// bm, err := cache.NewCache("memory", `{"interval":60}`)
+//
+// Use it like this:
+//
+//	bm.Put("astaxie", 1, 10 * time.Second)
+//	bm.Get("astaxie")
+//	bm.IsExist("astaxie")
+//	bm.Delete("astaxie")
+//
+//  more docs http://beego.me/docs/module/cache.md
+package cache
+
+import (
+	"fmt"
+	"time"
+)
+
+// Cache interface contains all behaviors for cache adapter.
+// usage:
+//	cache.Register("file",cache.NewFileCache) // this operation is run in init method of file.go.
+//	c,err := cache.NewCache("file","{....}")
+//	c.Put("key",value, 3600 * time.Second)
+//	v := c.Get("key")
+//
+//	c.Incr("counter")  // now is 1
+//	c.Incr("counter")  // now is 2
+//	count := c.Get("counter").(int)
+type Cache interface {
+	// get cached value by key.
+	Get(key string) interface{}
+	// GetMulti is a batch version of Get.
+	GetMulti(keys []string) []interface{}
+	// set cached value with key and expire time.
+	Put(key string, val interface{}, timeout time.Duration) error
+	// delete cached value by key.
+	Delete(key string) error
+	// increase cached int value by key, as a counter.
+	Incr(key string) error
+	// decrease cached int value by key, as a counter.
+	Decr(key string) error
+	// check if cached value exists or not.
+	IsExist(key string) bool
+	// clear all cache.
+	ClearAll() error
+	// start gc routine based on config string settings.
+	StartAndGC(config string) error
+}
+
+// Instance is a function create a new Cache Instance
+type Instance func() Cache
+
+var adapters = make(map[string]Instance)
+
+// Register makes a cache adapter available by the adapter name.
+// If Register is called twice with the same name or if driver is nil,
+// it panics.
+func Register(name string, adapter Instance) {
+	if adapter == nil {
+		panic("cache: Register adapter is nil")
+	}
+	if _, ok := adapters[name]; ok {
+		panic("cache: Register called twice for adapter " + name)
+	}
+	adapters[name] = adapter
+}
+
+// NewCache Create a new cache driver by adapter name and config string.
+// config need to be correct JSON as string: {"interval":360}.
+// it will start gc automatically.
+func NewCache(adapterName, config string) (adapter Cache, err error) {
+	instanceFunc, ok := adapters[adapterName]
+	if !ok {
+		err = fmt.Errorf("cache: unknown adapter name %q (forgot to import?)", adapterName)
+		return
+	}
+	adapter = instanceFunc()
+	err = adapter.StartAndGC(config)
+	if err != nil {
+		adapter = nil
+	}
+	return
+}

+ 168 - 0
vendor/github.com/fatedier/beego/cache/cache_test.go

@@ -0,0 +1,168 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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 (
+	"os"
+	"testing"
+	"time"
+)
+
+func TestCache(t *testing.T) {
+	bm, err := NewCache("memory", `{"interval":20}`)
+	if err != nil {
+		t.Error("init err")
+	}
+	timeoutDuration := 10 * time.Second
+	if err = bm.Put("astaxie", 1, timeoutDuration); err != nil {
+		t.Error("set Error", err)
+	}
+	if !bm.IsExist("astaxie") {
+		t.Error("check err")
+	}
+
+	if v := bm.Get("astaxie"); v.(int) != 1 {
+		t.Error("get err")
+	}
+
+	time.Sleep(30 * time.Second)
+
+	if bm.IsExist("astaxie") {
+		t.Error("check err")
+	}
+
+	if err = bm.Put("astaxie", 1, timeoutDuration); err != nil {
+		t.Error("set Error", err)
+	}
+
+	if err = bm.Incr("astaxie"); err != nil {
+		t.Error("Incr Error", err)
+	}
+
+	if v := bm.Get("astaxie"); v.(int) != 2 {
+		t.Error("get err")
+	}
+
+	if err = bm.Decr("astaxie"); err != nil {
+		t.Error("Decr Error", err)
+	}
+
+	if v := bm.Get("astaxie"); v.(int) != 1 {
+		t.Error("get err")
+	}
+	bm.Delete("astaxie")
+	if bm.IsExist("astaxie") {
+		t.Error("delete err")
+	}
+
+	//test GetMulti
+	if err = bm.Put("astaxie", "author", timeoutDuration); err != nil {
+		t.Error("set Error", err)
+	}
+	if !bm.IsExist("astaxie") {
+		t.Error("check err")
+	}
+	if v := bm.Get("astaxie"); v.(string) != "author" {
+		t.Error("get err")
+	}
+
+	if err = bm.Put("astaxie1", "author1", timeoutDuration); err != nil {
+		t.Error("set Error", err)
+	}
+	if !bm.IsExist("astaxie1") {
+		t.Error("check err")
+	}
+
+	vv := bm.GetMulti([]string{"astaxie", "astaxie1"})
+	if len(vv) != 2 {
+		t.Error("GetMulti ERROR")
+	}
+	if vv[0].(string) != "author" {
+		t.Error("GetMulti ERROR")
+	}
+	if vv[1].(string) != "author1" {
+		t.Error("GetMulti ERROR")
+	}
+}
+
+func TestFileCache(t *testing.T) {
+	bm, err := NewCache("file", `{"CachePath":"cache","FileSuffix":".bin","DirectoryLevel":2,"EmbedExpiry":0}`)
+	if err != nil {
+		t.Error("init err")
+	}
+	timeoutDuration := 10 * time.Second
+	if err = bm.Put("astaxie", 1, timeoutDuration); err != nil {
+		t.Error("set Error", err)
+	}
+	if !bm.IsExist("astaxie") {
+		t.Error("check err")
+	}
+
+	if v := bm.Get("astaxie"); v.(int) != 1 {
+		t.Error("get err")
+	}
+
+	if err = bm.Incr("astaxie"); err != nil {
+		t.Error("Incr Error", err)
+	}
+
+	if v := bm.Get("astaxie"); v.(int) != 2 {
+		t.Error("get err")
+	}
+
+	if err = bm.Decr("astaxie"); err != nil {
+		t.Error("Decr Error", err)
+	}
+
+	if v := bm.Get("astaxie"); v.(int) != 1 {
+		t.Error("get err")
+	}
+	bm.Delete("astaxie")
+	if bm.IsExist("astaxie") {
+		t.Error("delete err")
+	}
+
+	//test string
+	if err = bm.Put("astaxie", "author", timeoutDuration); err != nil {
+		t.Error("set Error", err)
+	}
+	if !bm.IsExist("astaxie") {
+		t.Error("check err")
+	}
+	if v := bm.Get("astaxie"); v.(string) != "author" {
+		t.Error("get err")
+	}
+
+	//test GetMulti
+	if err = bm.Put("astaxie1", "author1", timeoutDuration); err != nil {
+		t.Error("set Error", err)
+	}
+	if !bm.IsExist("astaxie1") {
+		t.Error("check err")
+	}
+
+	vv := bm.GetMulti([]string{"astaxie", "astaxie1"})
+	if len(vv) != 2 {
+		t.Error("GetMulti ERROR")
+	}
+	if vv[0].(string) != "author" {
+		t.Error("GetMulti ERROR")
+	}
+	if vv[1].(string) != "author1" {
+		t.Error("GetMulti ERROR")
+	}
+
+	os.RemoveAll("cache")
+}

+ 100 - 0
vendor/github.com/fatedier/beego/cache/conv.go

@@ -0,0 +1,100 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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"
+	"strconv"
+)
+
+// GetString convert interface to string.
+func GetString(v interface{}) string {
+	switch result := v.(type) {
+	case string:
+		return result
+	case []byte:
+		return string(result)
+	default:
+		if v != nil {
+			return fmt.Sprintf("%v", result)
+		}
+	}
+	return ""
+}
+
+// GetInt convert interface to int.
+func GetInt(v interface{}) int {
+	switch result := v.(type) {
+	case int:
+		return result
+	case int32:
+		return int(result)
+	case int64:
+		return int(result)
+	default:
+		if d := GetString(v); d != "" {
+			value, _ := strconv.Atoi(d)
+			return value
+		}
+	}
+	return 0
+}
+
+// GetInt64 convert interface to int64.
+func GetInt64(v interface{}) int64 {
+	switch result := v.(type) {
+	case int:
+		return int64(result)
+	case int32:
+		return int64(result)
+	case int64:
+		return result
+	default:
+
+		if d := GetString(v); d != "" {
+			value, _ := strconv.ParseInt(d, 10, 64)
+			return value
+		}
+	}
+	return 0
+}
+
+// GetFloat64 convert interface to float64.
+func GetFloat64(v interface{}) float64 {
+	switch result := v.(type) {
+	case float64:
+		return result
+	default:
+		if d := GetString(v); d != "" {
+			value, _ := strconv.ParseFloat(d, 64)
+			return value
+		}
+	}
+	return 0
+}
+
+// GetBool convert interface to bool.
+func GetBool(v interface{}) bool {
+	switch result := v.(type) {
+	case bool:
+		return result
+	default:
+		if d := GetString(v); d != "" {
+			value, _ := strconv.ParseBool(d)
+			return value
+		}
+	}
+	return false
+}

+ 143 - 0
vendor/github.com/fatedier/beego/cache/conv_test.go

@@ -0,0 +1,143 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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 (
+	"testing"
+)
+
+func TestGetString(t *testing.T) {
+	var t1 = "test1"
+	if "test1" != GetString(t1) {
+		t.Error("get string from string error")
+	}
+	var t2 = []byte("test2")
+	if "test2" != GetString(t2) {
+		t.Error("get string from byte array error")
+	}
+	var t3 = 1
+	if "1" != GetString(t3) {
+		t.Error("get string from int error")
+	}
+	var t4 int64 = 1
+	if "1" != GetString(t4) {
+		t.Error("get string from int64 error")
+	}
+	var t5 = 1.1
+	if "1.1" != GetString(t5) {
+		t.Error("get string from float64 error")
+	}
+
+	if "" != GetString(nil) {
+		t.Error("get string from nil error")
+	}
+}
+
+func TestGetInt(t *testing.T) {
+	var t1 = 1
+	if 1 != GetInt(t1) {
+		t.Error("get int from int error")
+	}
+	var t2 int32 = 32
+	if 32 != GetInt(t2) {
+		t.Error("get int from int32 error")
+	}
+	var t3 int64 = 64
+	if 64 != GetInt(t3) {
+		t.Error("get int from int64 error")
+	}
+	var t4 = "128"
+	if 128 != GetInt(t4) {
+		t.Error("get int from num string error")
+	}
+	if 0 != GetInt(nil) {
+		t.Error("get int from nil error")
+	}
+}
+
+func TestGetInt64(t *testing.T) {
+	var i int64 = 1
+	var t1 = 1
+	if i != GetInt64(t1) {
+		t.Error("get int64 from int error")
+	}
+	var t2 int32 = 1
+	if i != GetInt64(t2) {
+		t.Error("get int64 from int32 error")
+	}
+	var t3 int64 = 1
+	if i != GetInt64(t3) {
+		t.Error("get int64 from int64 error")
+	}
+	var t4 = "1"
+	if i != GetInt64(t4) {
+		t.Error("get int64 from num string error")
+	}
+	if 0 != GetInt64(nil) {
+		t.Error("get int64 from nil")
+	}
+}
+
+func TestGetFloat64(t *testing.T) {
+	var f = 1.11
+	var t1 float32 = 1.11
+	if f != GetFloat64(t1) {
+		t.Error("get float64 from float32 error")
+	}
+	var t2 = 1.11
+	if f != GetFloat64(t2) {
+		t.Error("get float64 from float64 error")
+	}
+	var t3 = "1.11"
+	if f != GetFloat64(t3) {
+		t.Error("get float64 from string error")
+	}
+
+	var f2 float64 = 1
+	var t4 = 1
+	if f2 != GetFloat64(t4) {
+		t.Error("get float64 from int error")
+	}
+
+	if 0 != GetFloat64(nil) {
+		t.Error("get float64 from nil error")
+	}
+}
+
+func TestGetBool(t *testing.T) {
+	var t1 = true
+	if true != GetBool(t1) {
+		t.Error("get bool from bool error")
+	}
+	var t2 = "true"
+	if true != GetBool(t2) {
+		t.Error("get bool from string error")
+	}
+	if false != GetBool(nil) {
+		t.Error("get bool from nil error")
+	}
+}
+
+func byteArrayEquals(a []byte, b []byte) bool {
+	if len(a) != len(b) {
+		return false
+	}
+	for i, v := range a {
+		if v != b[i] {
+			return false
+		}
+	}
+	return true
+}

+ 255 - 0
vendor/github.com/fatedier/beego/cache/file.go

@@ -0,0 +1,255 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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"
+	"crypto/md5"
+	"encoding/gob"
+	"encoding/hex"
+	"encoding/json"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"reflect"
+	"strconv"
+	"time"
+)
+
+// FileCacheItem is basic unit of file cache adapter.
+// it contains data and expire time.
+type FileCacheItem struct {
+	Data       interface{}
+	Lastaccess time.Time
+	Expired    time.Time
+}
+
+// FileCache Config
+var (
+	FileCachePath           = "cache"     // cache directory
+	FileCacheFileSuffix     = ".bin"      // cache file suffix
+	FileCacheDirectoryLevel = 2           // cache file deep level if auto generated cache files.
+	FileCacheEmbedExpiry    time.Duration // cache expire time, default is no expire forever.
+)
+
+// FileCache is cache adapter for file storage.
+type FileCache struct {
+	CachePath      string
+	FileSuffix     string
+	DirectoryLevel int
+	EmbedExpiry    int
+}
+
+// NewFileCache Create new file cache with no config.
+// the level and expiry need set in method StartAndGC as config string.
+func NewFileCache() Cache {
+	//    return &FileCache{CachePath:FileCachePath, FileSuffix:FileCacheFileSuffix}
+	return &FileCache{}
+}
+
+// StartAndGC will start and begin gc for file cache.
+// the config need to be like {CachePath:"/cache","FileSuffix":".bin","DirectoryLevel":2,"EmbedExpiry":0}
+func (fc *FileCache) StartAndGC(config string) error {
+
+	var cfg map[string]string
+	json.Unmarshal([]byte(config), &cfg)
+	if _, ok := cfg["CachePath"]; !ok {
+		cfg["CachePath"] = FileCachePath
+	}
+	if _, ok := cfg["FileSuffix"]; !ok {
+		cfg["FileSuffix"] = FileCacheFileSuffix
+	}
+	if _, ok := cfg["DirectoryLevel"]; !ok {
+		cfg["DirectoryLevel"] = strconv.Itoa(FileCacheDirectoryLevel)
+	}
+	if _, ok := cfg["EmbedExpiry"]; !ok {
+		cfg["EmbedExpiry"] = strconv.FormatInt(int64(FileCacheEmbedExpiry.Seconds()), 10)
+	}
+	fc.CachePath = cfg["CachePath"]
+	fc.FileSuffix = cfg["FileSuffix"]
+	fc.DirectoryLevel, _ = strconv.Atoi(cfg["DirectoryLevel"])
+	fc.EmbedExpiry, _ = strconv.Atoi(cfg["EmbedExpiry"])
+
+	fc.Init()
+	return nil
+}
+
+// Init will make new dir for file cache if not exist.
+func (fc *FileCache) Init() {
+	if ok, _ := exists(fc.CachePath); !ok { // todo : error handle
+		_ = os.MkdirAll(fc.CachePath, os.ModePerm) // todo : error handle
+	}
+}
+
+// get cached file name. it's md5 encoded.
+func (fc *FileCache) getCacheFileName(key string) string {
+	m := md5.New()
+	io.WriteString(m, key)
+	keyMd5 := hex.EncodeToString(m.Sum(nil))
+	cachePath := fc.CachePath
+	switch fc.DirectoryLevel {
+	case 2:
+		cachePath = filepath.Join(cachePath, keyMd5[0:2], keyMd5[2:4])
+	case 1:
+		cachePath = filepath.Join(cachePath, keyMd5[0:2])
+	}
+
+	if ok, _ := exists(cachePath); !ok { // todo : error handle
+		_ = os.MkdirAll(cachePath, os.ModePerm) // todo : error handle
+	}
+
+	return filepath.Join(cachePath, fmt.Sprintf("%s%s", keyMd5, fc.FileSuffix))
+}
+
+// Get value from file cache.
+// if non-exist or expired, return empty string.
+func (fc *FileCache) Get(key string) interface{} {
+	fileData, err := FileGetContents(fc.getCacheFileName(key))
+	if err != nil {
+		return ""
+	}
+	var to FileCacheItem
+	GobDecode(fileData, &to)
+	if to.Expired.Before(time.Now()) {
+		return ""
+	}
+	return to.Data
+}
+
+// GetMulti gets values from file cache.
+// if non-exist or expired, return empty string.
+func (fc *FileCache) GetMulti(keys []string) []interface{} {
+	var rc []interface{}
+	for _, key := range keys {
+		rc = append(rc, fc.Get(key))
+	}
+	return rc
+}
+
+// Put value into file cache.
+// timeout means how long to keep this file, unit of ms.
+// if timeout equals FileCacheEmbedExpiry(default is 0), cache this item forever.
+func (fc *FileCache) Put(key string, val interface{}, timeout time.Duration) error {
+	gob.Register(val)
+
+	item := FileCacheItem{Data: val}
+	if timeout == FileCacheEmbedExpiry {
+		item.Expired = time.Now().Add((86400 * 365 * 10) * time.Second) // ten years
+	} else {
+		item.Expired = time.Now().Add(timeout)
+	}
+	item.Lastaccess = time.Now()
+	data, err := GobEncode(item)
+	if err != nil {
+		return err
+	}
+	return FilePutContents(fc.getCacheFileName(key), data)
+}
+
+// Delete file cache value.
+func (fc *FileCache) Delete(key string) error {
+	filename := fc.getCacheFileName(key)
+	if ok, _ := exists(filename); ok {
+		return os.Remove(filename)
+	}
+	return nil
+}
+
+// Incr will increase cached int value.
+// fc value is saving forever unless Delete.
+func (fc *FileCache) Incr(key string) error {
+	data := fc.Get(key)
+	var incr int
+	if reflect.TypeOf(data).Name() != "int" {
+		incr = 0
+	} else {
+		incr = data.(int) + 1
+	}
+	fc.Put(key, incr, FileCacheEmbedExpiry)
+	return nil
+}
+
+// Decr will decrease cached int value.
+func (fc *FileCache) Decr(key string) error {
+	data := fc.Get(key)
+	var decr int
+	if reflect.TypeOf(data).Name() != "int" || data.(int)-1 <= 0 {
+		decr = 0
+	} else {
+		decr = data.(int) - 1
+	}
+	fc.Put(key, decr, FileCacheEmbedExpiry)
+	return nil
+}
+
+// IsExist check value is exist.
+func (fc *FileCache) IsExist(key string) bool {
+	ret, _ := exists(fc.getCacheFileName(key))
+	return ret
+}
+
+// ClearAll will clean cached files.
+// not implemented.
+func (fc *FileCache) ClearAll() error {
+	return nil
+}
+
+// check file exist.
+func exists(path string) (bool, error) {
+	_, err := os.Stat(path)
+	if err == nil {
+		return true, nil
+	}
+	if os.IsNotExist(err) {
+		return false, nil
+	}
+	return false, err
+}
+
+// FileGetContents Get bytes to file.
+// if non-exist, create this file.
+func FileGetContents(filename string) (data []byte, e error) {
+	return ioutil.ReadFile(filename)
+}
+
+// FilePutContents Put bytes to file.
+// if non-exist, create this file.
+func FilePutContents(filename string, content []byte) error {
+	return ioutil.WriteFile(filename, content, os.ModePerm)
+}
+
+// GobEncode Gob encodes file cache item.
+func GobEncode(data interface{}) ([]byte, error) {
+	buf := bytes.NewBuffer(nil)
+	enc := gob.NewEncoder(buf)
+	err := enc.Encode(data)
+	if err != nil {
+		return nil, err
+	}
+	return buf.Bytes(), err
+}
+
+// GobDecode Gob decodes file cache item.
+func GobDecode(data []byte, to *FileCacheItem) error {
+	buf := bytes.NewBuffer(data)
+	dec := gob.NewDecoder(buf)
+	return dec.Decode(&to)
+}
+
+func init() {
+	Register("file", NewFileCache)
+}

+ 191 - 0
vendor/github.com/fatedier/beego/cache/memcache/memcache.go

@@ -0,0 +1,191 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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 for cache provider
+//
+// depend on github.com/bradfitz/gomemcache/memcache
+//
+// go install github.com/bradfitz/gomemcache/memcache
+//
+// Usage:
+// import(
+//   _ "github.com/astaxie/beego/cache/memcache"
+//   "github.com/astaxie/beego/cache"
+// )
+//
+//  bm, err := cache.NewCache("memcache", `{"conn":"127.0.0.1:11211"}`)
+//
+//  more docs http://beego.me/docs/module/cache.md
+package memcache
+
+import (
+	"encoding/json"
+	"errors"
+	"strings"
+	"time"
+
+	"github.com/astaxie/beego/cache"
+	"github.com/bradfitz/gomemcache/memcache"
+)
+
+// Cache Memcache adapter.
+type Cache struct {
+	conn     *memcache.Client
+	conninfo []string
+}
+
+// NewMemCache create new memcache adapter.
+func NewMemCache() cache.Cache {
+	return &Cache{}
+}
+
+// Get get value from memcache.
+func (rc *Cache) Get(key string) interface{} {
+	if rc.conn == nil {
+		if err := rc.connectInit(); err != nil {
+			return err
+		}
+	}
+	if item, err := rc.conn.Get(key); err == nil {
+		return item.Value
+	}
+	return nil
+}
+
+// GetMulti get value from memcache.
+func (rc *Cache) GetMulti(keys []string) []interface{} {
+	size := len(keys)
+	var rv []interface{}
+	if rc.conn == nil {
+		if err := rc.connectInit(); err != nil {
+			for i := 0; i < size; i++ {
+				rv = append(rv, err)
+			}
+			return rv
+		}
+	}
+	mv, err := rc.conn.GetMulti(keys)
+	if err == nil {
+		for _, v := range mv {
+			rv = append(rv, v.Value)
+		}
+		return rv
+	}
+	for i := 0; i < size; i++ {
+		rv = append(rv, err)
+	}
+	return rv
+}
+
+// Put put value to memcache.
+func (rc *Cache) Put(key string, val interface{}, timeout time.Duration) error {
+	if rc.conn == nil {
+		if err := rc.connectInit(); err != nil {
+			return err
+		}
+	}
+	item := memcache.Item{Key: key, Expiration: int32(timeout / time.Second)}
+	if v, ok := val.([]byte); ok {
+		item.Value = v
+	} else if str, ok := val.(string); ok {
+		item.Value = []byte(str)
+	} else {
+		return errors.New("val only support string and []byte")
+	}
+	return rc.conn.Set(&item)
+}
+
+// Delete delete value in memcache.
+func (rc *Cache) Delete(key string) error {
+	if rc.conn == nil {
+		if err := rc.connectInit(); err != nil {
+			return err
+		}
+	}
+	return rc.conn.Delete(key)
+}
+
+// Incr increase counter.
+func (rc *Cache) Incr(key string) error {
+	if rc.conn == nil {
+		if err := rc.connectInit(); err != nil {
+			return err
+		}
+	}
+	_, err := rc.conn.Increment(key, 1)
+	return err
+}
+
+// Decr decrease counter.
+func (rc *Cache) Decr(key string) error {
+	if rc.conn == nil {
+		if err := rc.connectInit(); err != nil {
+			return err
+		}
+	}
+	_, err := rc.conn.Decrement(key, 1)
+	return err
+}
+
+// IsExist check value exists in memcache.
+func (rc *Cache) IsExist(key string) bool {
+	if rc.conn == nil {
+		if err := rc.connectInit(); err != nil {
+			return false
+		}
+	}
+	_, err := rc.conn.Get(key)
+	if err != nil {
+		return false
+	}
+	return true
+}
+
+// ClearAll clear all cached in memcache.
+func (rc *Cache) ClearAll() error {
+	if rc.conn == nil {
+		if err := rc.connectInit(); err != nil {
+			return err
+		}
+	}
+	return rc.conn.FlushAll()
+}
+
+// StartAndGC start memcache adapter.
+// config string is like {"conn":"connection info"}.
+// if connecting error, return.
+func (rc *Cache) StartAndGC(config string) error {
+	var cf map[string]string
+	json.Unmarshal([]byte(config), &cf)
+	if _, ok := cf["conn"]; !ok {
+		return errors.New("config has no conn key")
+	}
+	rc.conninfo = strings.Split(cf["conn"], ";")
+	if rc.conn == nil {
+		if err := rc.connectInit(); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// connect to memcache and keep the connection.
+func (rc *Cache) connectInit() error {
+	rc.conn = memcache.New(rc.conninfo...)
+	return nil
+}
+
+func init() {
+	cache.Register("memcache", NewMemCache)
+}

+ 108 - 0
vendor/github.com/fatedier/beego/cache/memcache/memcache_test.go

@@ -0,0 +1,108 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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 (
+	_ "github.com/bradfitz/gomemcache/memcache"
+
+	"strconv"
+	"testing"
+	"time"
+
+	"github.com/astaxie/beego/cache"
+)
+
+func TestMemcacheCache(t *testing.T) {
+	bm, err := cache.NewCache("memcache", `{"conn": "127.0.0.1:11211"}`)
+	if err != nil {
+		t.Error("init err")
+	}
+	timeoutDuration := 10 * time.Second
+	if err = bm.Put("astaxie", "1", timeoutDuration); err != nil {
+		t.Error("set Error", err)
+	}
+	if !bm.IsExist("astaxie") {
+		t.Error("check err")
+	}
+
+	time.Sleep(11 * time.Second)
+
+	if bm.IsExist("astaxie") {
+		t.Error("check err")
+	}
+	if err = bm.Put("astaxie", "1", timeoutDuration); err != nil {
+		t.Error("set Error", err)
+	}
+
+	if v, err := strconv.Atoi(string(bm.Get("astaxie").([]byte))); err != nil || v != 1 {
+		t.Error("get err")
+	}
+
+	if err = bm.Incr("astaxie"); err != nil {
+		t.Error("Incr Error", err)
+	}
+
+	if v, err := strconv.Atoi(string(bm.Get("astaxie").([]byte))); err != nil || v != 2 {
+		t.Error("get err")
+	}
+
+	if err = bm.Decr("astaxie"); err != nil {
+		t.Error("Decr Error", err)
+	}
+
+	if v, err := strconv.Atoi(string(bm.Get("astaxie").([]byte))); err != nil || v != 1 {
+		t.Error("get err")
+	}
+	bm.Delete("astaxie")
+	if bm.IsExist("astaxie") {
+		t.Error("delete err")
+	}
+
+	//test string
+	if err = bm.Put("astaxie", "author", timeoutDuration); err != nil {
+		t.Error("set Error", err)
+	}
+	if !bm.IsExist("astaxie") {
+		t.Error("check err")
+	}
+
+	if v := bm.Get("astaxie").([]byte); string(v) != "author" {
+		t.Error("get err")
+	}
+
+	//test GetMulti
+	if err = bm.Put("astaxie1", "author1", timeoutDuration); err != nil {
+		t.Error("set Error", err)
+	}
+	if !bm.IsExist("astaxie1") {
+		t.Error("check err")
+	}
+
+	vv := bm.GetMulti([]string{"astaxie", "astaxie1"})
+	if len(vv) != 2 {
+		t.Error("GetMulti ERROR")
+	}
+	if string(vv[0].([]byte)) != "author" && string(vv[0].([]byte)) != "author1" {
+		t.Error("GetMulti ERROR")
+	}
+	if string(vv[1].([]byte)) != "author1" && string(vv[1].([]byte)) != "author" {
+		t.Error("GetMulti ERROR")
+	}
+
+	// test clear all
+	if err = bm.ClearAll(); err != nil {
+		t.Error("clear all err")
+	}
+}

+ 244 - 0
vendor/github.com/fatedier/beego/cache/memory.go

@@ -0,0 +1,244 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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 (
+	"encoding/json"
+	"errors"
+	"sync"
+	"time"
+)
+
+var (
+	// DefaultEvery means the clock time of recycling the expired cache items in memory.
+	DefaultEvery = 60 // 1 minute
+)
+
+// MemoryItem store memory cache item.
+type MemoryItem struct {
+	val         interface{}
+	createdTime time.Time
+	lifespan    time.Duration
+}
+
+func (mi *MemoryItem) isExpire() bool {
+	// 0 means forever
+	if mi.lifespan == 0 {
+		return false
+	}
+	return time.Now().Sub(mi.createdTime) > mi.lifespan
+}
+
+// MemoryCache is Memory cache adapter.
+// it contains a RW locker for safe map storage.
+type MemoryCache struct {
+	sync.RWMutex
+	dur   time.Duration
+	items map[string]*MemoryItem
+	Every int // run an expiration check Every clock time
+}
+
+// NewMemoryCache returns a new MemoryCache.
+func NewMemoryCache() Cache {
+	cache := MemoryCache{items: make(map[string]*MemoryItem)}
+	return &cache
+}
+
+// Get cache from memory.
+// if non-existed or expired, return nil.
+func (bc *MemoryCache) Get(name string) interface{} {
+	bc.RLock()
+	defer bc.RUnlock()
+	if itm, ok := bc.items[name]; ok {
+		if itm.isExpire() {
+			return nil
+		}
+		return itm.val
+	}
+	return nil
+}
+
+// GetMulti gets caches from memory.
+// if non-existed or expired, return nil.
+func (bc *MemoryCache) GetMulti(names []string) []interface{} {
+	var rc []interface{}
+	for _, name := range names {
+		rc = append(rc, bc.Get(name))
+	}
+	return rc
+}
+
+// Put cache to memory.
+// if lifespan is 0, it will be forever till restart.
+func (bc *MemoryCache) Put(name string, value interface{}, lifespan time.Duration) error {
+	bc.Lock()
+	defer bc.Unlock()
+	bc.items[name] = &MemoryItem{
+		val:         value,
+		createdTime: time.Now(),
+		lifespan:    lifespan,
+	}
+	return nil
+}
+
+// Delete cache in memory.
+func (bc *MemoryCache) Delete(name string) error {
+	bc.Lock()
+	defer bc.Unlock()
+	if _, ok := bc.items[name]; !ok {
+		return errors.New("key not exist")
+	}
+	delete(bc.items, name)
+	if _, ok := bc.items[name]; ok {
+		return errors.New("delete key error")
+	}
+	return nil
+}
+
+// Incr increase cache counter in memory.
+// it supports int,int32,int64,uint,uint32,uint64.
+func (bc *MemoryCache) Incr(key string) error {
+	bc.RLock()
+	defer bc.RUnlock()
+	itm, ok := bc.items[key]
+	if !ok {
+		return errors.New("key not exist")
+	}
+	switch itm.val.(type) {
+	case int:
+		itm.val = itm.val.(int) + 1
+	case int32:
+		itm.val = itm.val.(int32) + 1
+	case int64:
+		itm.val = itm.val.(int64) + 1
+	case uint:
+		itm.val = itm.val.(uint) + 1
+	case uint32:
+		itm.val = itm.val.(uint32) + 1
+	case uint64:
+		itm.val = itm.val.(uint64) + 1
+	default:
+		return errors.New("item val is not (u)int (u)int32 (u)int64")
+	}
+	return nil
+}
+
+// Decr decrease counter in memory.
+func (bc *MemoryCache) Decr(key string) error {
+	bc.RLock()
+	defer bc.RUnlock()
+	itm, ok := bc.items[key]
+	if !ok {
+		return errors.New("key not exist")
+	}
+	switch itm.val.(type) {
+	case int:
+		itm.val = itm.val.(int) - 1
+	case int64:
+		itm.val = itm.val.(int64) - 1
+	case int32:
+		itm.val = itm.val.(int32) - 1
+	case uint:
+		if itm.val.(uint) > 0 {
+			itm.val = itm.val.(uint) - 1
+		} else {
+			return errors.New("item val is less than 0")
+		}
+	case uint32:
+		if itm.val.(uint32) > 0 {
+			itm.val = itm.val.(uint32) - 1
+		} else {
+			return errors.New("item val is less than 0")
+		}
+	case uint64:
+		if itm.val.(uint64) > 0 {
+			itm.val = itm.val.(uint64) - 1
+		} else {
+			return errors.New("item val is less than 0")
+		}
+	default:
+		return errors.New("item val is not int int64 int32")
+	}
+	return nil
+}
+
+// IsExist check cache exist in memory.
+func (bc *MemoryCache) IsExist(name string) bool {
+	bc.RLock()
+	defer bc.RUnlock()
+	if v, ok := bc.items[name]; ok {
+		return !v.isExpire()
+	}
+	return false
+}
+
+// ClearAll will delete all cache in memory.
+func (bc *MemoryCache) ClearAll() error {
+	bc.Lock()
+	defer bc.Unlock()
+	bc.items = make(map[string]*MemoryItem)
+	return nil
+}
+
+// StartAndGC start memory cache. it will check expiration in every clock time.
+func (bc *MemoryCache) StartAndGC(config string) error {
+	var cf map[string]int
+	json.Unmarshal([]byte(config), &cf)
+	if _, ok := cf["interval"]; !ok {
+		cf = make(map[string]int)
+		cf["interval"] = DefaultEvery
+	}
+	dur := time.Duration(cf["interval"]) * time.Second
+	bc.Every = cf["interval"]
+	bc.dur = dur
+	go bc.vaccuum()
+	return nil
+}
+
+// check expiration.
+func (bc *MemoryCache) vaccuum() {
+	if bc.Every < 1 {
+		return
+	}
+	for {
+		<-time.After(bc.dur)
+		if bc.items == nil {
+			return
+		}
+		for name := range bc.items {
+			bc.itemExpired(name)
+		}
+	}
+}
+
+// itemExpired returns true if an item is expired.
+func (bc *MemoryCache) itemExpired(name string) bool {
+	bc.Lock()
+	defer bc.Unlock()
+
+	itm, ok := bc.items[name]
+	if !ok {
+		return true
+	}
+	if itm.isExpire() {
+		delete(bc.items, name)
+		return true
+	}
+	return false
+}
+
+func init() {
+	Register("memory", NewMemoryCache)
+}

+ 240 - 0
vendor/github.com/fatedier/beego/cache/redis/redis.go

@@ -0,0 +1,240 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package redis for cache provider
+//
+// depend on github.com/garyburd/redigo/redis
+//
+// go install github.com/garyburd/redigo/redis
+//
+// Usage:
+// import(
+//   _ "github.com/astaxie/beego/cache/redis"
+//   "github.com/astaxie/beego/cache"
+// )
+//
+//  bm, err := cache.NewCache("redis", `{"conn":"127.0.0.1:11211"}`)
+//
+//  more docs http://beego.me/docs/module/cache.md
+package redis
+
+import (
+	"encoding/json"
+	"errors"
+	"strconv"
+	"time"
+
+	"github.com/garyburd/redigo/redis"
+
+	"github.com/astaxie/beego/cache"
+)
+
+var (
+	// DefaultKey the collection name of redis for cache adapter.
+	DefaultKey = "beecacheRedis"
+)
+
+// Cache is Redis cache adapter.
+type Cache struct {
+	p        *redis.Pool // redis connection pool
+	conninfo string
+	dbNum    int
+	key      string
+	password string
+}
+
+// NewRedisCache create new redis cache with default collection name.
+func NewRedisCache() cache.Cache {
+	return &Cache{key: DefaultKey}
+}
+
+// actually do the redis cmds
+func (rc *Cache) do(commandName string, args ...interface{}) (reply interface{}, err error) {
+	c := rc.p.Get()
+	defer c.Close()
+
+	return c.Do(commandName, args...)
+}
+
+// Get cache from redis.
+func (rc *Cache) Get(key string) interface{} {
+	if v, err := rc.do("GET", key); err == nil {
+		return v
+	}
+	return nil
+}
+
+// GetMulti get cache from redis.
+func (rc *Cache) GetMulti(keys []string) []interface{} {
+	size := len(keys)
+	var rv []interface{}
+	c := rc.p.Get()
+	defer c.Close()
+	var err error
+	for _, key := range keys {
+		err = c.Send("GET", key)
+		if err != nil {
+			goto ERROR
+		}
+	}
+	if err = c.Flush(); err != nil {
+		goto ERROR
+	}
+	for i := 0; i < size; i++ {
+		if v, err := c.Receive(); err == nil {
+			rv = append(rv, v.([]byte))
+		} else {
+			rv = append(rv, err)
+		}
+	}
+	return rv
+ERROR:
+	rv = rv[0:0]
+	for i := 0; i < size; i++ {
+		rv = append(rv, nil)
+	}
+
+	return rv
+}
+
+// Put put cache to redis.
+func (rc *Cache) Put(key string, val interface{}, timeout time.Duration) error {
+	var err error
+	if _, err = rc.do("SETEX", key, int64(timeout/time.Second), val); err != nil {
+		return err
+	}
+
+	if _, err = rc.do("HSET", rc.key, key, true); err != nil {
+		return err
+	}
+	return err
+}
+
+// Delete delete cache in redis.
+func (rc *Cache) Delete(key string) error {
+	var err error
+	if _, err = rc.do("DEL", key); err != nil {
+		return err
+	}
+	_, err = rc.do("HDEL", rc.key, key)
+	return err
+}
+
+// IsExist check cache's existence in redis.
+func (rc *Cache) IsExist(key string) bool {
+	v, err := redis.Bool(rc.do("EXISTS", key))
+	if err != nil {
+		return false
+	}
+	if v == false {
+		if _, err = rc.do("HDEL", rc.key, key); err != nil {
+			return false
+		}
+	}
+	return v
+}
+
+// Incr increase counter in redis.
+func (rc *Cache) Incr(key string) error {
+	_, err := redis.Bool(rc.do("INCRBY", key, 1))
+	return err
+}
+
+// Decr decrease counter in redis.
+func (rc *Cache) Decr(key string) error {
+	_, err := redis.Bool(rc.do("INCRBY", key, -1))
+	return err
+}
+
+// ClearAll clean all cache in redis. delete this redis collection.
+func (rc *Cache) ClearAll() error {
+	cachedKeys, err := redis.Strings(rc.do("HKEYS", rc.key))
+	if err != nil {
+		return err
+	}
+	for _, str := range cachedKeys {
+		if _, err = rc.do("DEL", str); err != nil {
+			return err
+		}
+	}
+	_, err = rc.do("DEL", rc.key)
+	return err
+}
+
+// StartAndGC start redis cache adapter.
+// config is like {"key":"collection key","conn":"connection info","dbNum":"0"}
+// the cache item in redis are stored forever,
+// so no gc operation.
+func (rc *Cache) StartAndGC(config string) error {
+	var cf map[string]string
+	json.Unmarshal([]byte(config), &cf)
+
+	if _, ok := cf["key"]; !ok {
+		cf["key"] = DefaultKey
+	}
+	if _, ok := cf["conn"]; !ok {
+		return errors.New("config has no conn key")
+	}
+	if _, ok := cf["dbNum"]; !ok {
+		cf["dbNum"] = "0"
+	}
+	if _, ok := cf["password"]; !ok {
+		cf["password"] = ""
+	}
+	rc.key = cf["key"]
+	rc.conninfo = cf["conn"]
+	rc.dbNum, _ = strconv.Atoi(cf["dbNum"])
+	rc.password = cf["password"]
+
+	rc.connectInit()
+
+	c := rc.p.Get()
+	defer c.Close()
+
+	return c.Err()
+}
+
+// connect to redis.
+func (rc *Cache) connectInit() {
+	dialFunc := func() (c redis.Conn, err error) {
+		c, err = redis.Dial("tcp", rc.conninfo)
+		if err != nil {
+			return nil, err
+		}
+
+		if rc.password != "" {
+			if _, err := c.Do("AUTH", rc.password); err != nil {
+				c.Close()
+				return nil, err
+			}
+		}
+
+		_, selecterr := c.Do("SELECT", rc.dbNum)
+		if selecterr != nil {
+			c.Close()
+			return nil, selecterr
+		}
+		return
+	}
+	// initialize a new pool
+	rc.p = &redis.Pool{
+		MaxIdle:     3,
+		IdleTimeout: 180 * time.Second,
+		Dial:        dialFunc,
+	}
+}
+
+func init() {
+	cache.Register("redis", NewRedisCache)
+}

+ 106 - 0
vendor/github.com/fatedier/beego/cache/redis/redis_test.go

@@ -0,0 +1,106 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package redis
+
+import (
+	"testing"
+	"time"
+
+	"github.com/astaxie/beego/cache"
+	"github.com/garyburd/redigo/redis"
+)
+
+func TestRedisCache(t *testing.T) {
+	bm, err := cache.NewCache("redis", `{"conn": "127.0.0.1:6379"}`)
+	if err != nil {
+		t.Error("init err")
+	}
+	timeoutDuration := 10 * time.Second
+	if err = bm.Put("astaxie", 1, timeoutDuration); err != nil {
+		t.Error("set Error", err)
+	}
+	if !bm.IsExist("astaxie") {
+		t.Error("check err")
+	}
+
+	time.Sleep(11 * time.Second)
+
+	if bm.IsExist("astaxie") {
+		t.Error("check err")
+	}
+	if err = bm.Put("astaxie", 1, timeoutDuration); err != nil {
+		t.Error("set Error", err)
+	}
+
+	if v, _ := redis.Int(bm.Get("astaxie"), err); v != 1 {
+		t.Error("get err")
+	}
+
+	if err = bm.Incr("astaxie"); err != nil {
+		t.Error("Incr Error", err)
+	}
+
+	if v, _ := redis.Int(bm.Get("astaxie"), err); v != 2 {
+		t.Error("get err")
+	}
+
+	if err = bm.Decr("astaxie"); err != nil {
+		t.Error("Decr Error", err)
+	}
+
+	if v, _ := redis.Int(bm.Get("astaxie"), err); v != 1 {
+		t.Error("get err")
+	}
+	bm.Delete("astaxie")
+	if bm.IsExist("astaxie") {
+		t.Error("delete err")
+	}
+
+	//test string
+	if err = bm.Put("astaxie", "author", timeoutDuration); err != nil {
+		t.Error("set Error", err)
+	}
+	if !bm.IsExist("astaxie") {
+		t.Error("check err")
+	}
+
+	if v, _ := redis.String(bm.Get("astaxie"), err); v != "author" {
+		t.Error("get err")
+	}
+
+	//test GetMulti
+	if err = bm.Put("astaxie1", "author1", timeoutDuration); err != nil {
+		t.Error("set Error", err)
+	}
+	if !bm.IsExist("astaxie1") {
+		t.Error("check err")
+	}
+
+	vv := bm.GetMulti([]string{"astaxie", "astaxie1"})
+	if len(vv) != 2 {
+		t.Error("GetMulti ERROR")
+	}
+	if v, _ := redis.String(vv[0], nil); v != "author" {
+		t.Error("GetMulti ERROR")
+	}
+	if v, _ := redis.String(vv[1], nil); v != "author1" {
+		t.Error("GetMulti ERROR")
+	}
+
+	// test clear all
+	if err = bm.ClearAll(); err != nil {
+		t.Error("clear all err")
+	}
+}

+ 240 - 0
vendor/github.com/fatedier/beego/cache/ssdb/ssdb.go

@@ -0,0 +1,240 @@
+package ssdb
+
+import (
+	"encoding/json"
+	"errors"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/ssdb/gossdb/ssdb"
+
+	"github.com/astaxie/beego/cache"
+)
+
+// Cache SSDB adapter
+type Cache struct {
+	conn     *ssdb.Client
+	conninfo []string
+}
+
+//NewSsdbCache create new ssdb adapter.
+func NewSsdbCache() cache.Cache {
+	return &Cache{}
+}
+
+// Get get value from memcache.
+func (rc *Cache) Get(key string) interface{} {
+	if rc.conn == nil {
+		if err := rc.connectInit(); err != nil {
+			return nil
+		}
+	}
+	value, err := rc.conn.Get(key)
+	if err == nil {
+		return value
+	}
+	return nil
+}
+
+// GetMulti get value from memcache.
+func (rc *Cache) GetMulti(keys []string) []interface{} {
+	size := len(keys)
+	var values []interface{}
+	if rc.conn == nil {
+		if err := rc.connectInit(); err != nil {
+			for i := 0; i < size; i++ {
+				values = append(values, err)
+			}
+			return values
+		}
+	}
+	res, err := rc.conn.Do("multi_get", keys)
+	resSize := len(res)
+	if err == nil {
+		for i := 1; i < resSize; i += 2 {
+			values = append(values, string(res[i+1]))
+		}
+		return values
+	}
+	for i := 0; i < size; i++ {
+		values = append(values, err)
+	}
+	return values
+}
+
+// DelMulti get value from memcache.
+func (rc *Cache) DelMulti(keys []string) error {
+	if rc.conn == nil {
+		if err := rc.connectInit(); err != nil {
+			return err
+		}
+	}
+	_, err := rc.conn.Do("multi_del", keys)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+// Put put value to memcache. only support string.
+func (rc *Cache) Put(key string, value interface{}, timeout time.Duration) error {
+	if rc.conn == nil {
+		if err := rc.connectInit(); err != nil {
+			return err
+		}
+	}
+	v, ok := value.(string)
+	if !ok {
+		return errors.New("value must string")
+	}
+	var resp []string
+	var err error
+	ttl := int(timeout / time.Second)
+	if ttl < 0 {
+		resp, err = rc.conn.Do("set", key, v)
+	} else {
+		resp, err = rc.conn.Do("setx", key, v, ttl)
+	}
+	if err != nil {
+		return err
+	}
+	if len(resp) == 2 && resp[0] == "ok" {
+		return nil
+	}
+	return errors.New("bad response")
+}
+
+// Delete delete value in memcache.
+func (rc *Cache) Delete(key string) error {
+	if rc.conn == nil {
+		if err := rc.connectInit(); err != nil {
+			return err
+		}
+	}
+	_, err := rc.conn.Del(key)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+// Incr increase counter.
+func (rc *Cache) Incr(key string) error {
+	if rc.conn == nil {
+		if err := rc.connectInit(); err != nil {
+			return err
+		}
+	}
+	_, err := rc.conn.Do("incr", key, 1)
+	return err
+}
+
+// Decr decrease counter.
+func (rc *Cache) Decr(key string) error {
+	if rc.conn == nil {
+		if err := rc.connectInit(); err != nil {
+			return err
+		}
+	}
+	_, err := rc.conn.Do("incr", key, -1)
+	return err
+}
+
+// IsExist check value exists in memcache.
+func (rc *Cache) IsExist(key string) bool {
+	if rc.conn == nil {
+		if err := rc.connectInit(); err != nil {
+			return false
+		}
+	}
+	resp, err := rc.conn.Do("exists", key)
+	if err != nil {
+		return false
+	}
+	if len(resp) == 2 && resp[1] == "1" {
+		return true
+	}
+	return false
+
+}
+
+// ClearAll clear all cached in memcache.
+func (rc *Cache) ClearAll() error {
+	if rc.conn == nil {
+		if err := rc.connectInit(); err != nil {
+			return err
+		}
+	}
+	keyStart, keyEnd, limit := "", "", 50
+	resp, err := rc.Scan(keyStart, keyEnd, limit)
+	for err == nil {
+		size := len(resp)
+		if size == 1 {
+			return nil
+		}
+		keys := []string{}
+		for i := 1; i < size; i += 2 {
+			keys = append(keys, string(resp[i]))
+		}
+		_, e := rc.conn.Do("multi_del", keys)
+		if e != nil {
+			return e
+		}
+		keyStart = resp[size-2]
+		resp, err = rc.Scan(keyStart, keyEnd, limit)
+	}
+	return err
+}
+
+// Scan key all cached in ssdb.
+func (rc *Cache) Scan(keyStart string, keyEnd string, limit int) ([]string, error) {
+	if rc.conn == nil {
+		if err := rc.connectInit(); err != nil {
+			return nil, err
+		}
+	}
+	resp, err := rc.conn.Do("scan", keyStart, keyEnd, limit)
+	if err != nil {
+		return nil, err
+	}
+	return resp, nil
+}
+
+// StartAndGC start memcache adapter.
+// config string is like {"conn":"connection info"}.
+// if connecting error, return.
+func (rc *Cache) StartAndGC(config string) error {
+	var cf map[string]string
+	json.Unmarshal([]byte(config), &cf)
+	if _, ok := cf["conn"]; !ok {
+		return errors.New("config has no conn key")
+	}
+	rc.conninfo = strings.Split(cf["conn"], ";")
+	if rc.conn == nil {
+		if err := rc.connectInit(); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// connect to memcache and keep the connection.
+func (rc *Cache) connectInit() error {
+	conninfoArray := strings.Split(rc.conninfo[0], ":")
+	host := conninfoArray[0]
+	port, e := strconv.Atoi(conninfoArray[1])
+	if e != nil {
+		return e
+	}
+	var err error
+	rc.conn, err = ssdb.Connect(host, port)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func init() {
+	cache.Register("ssdb", NewSsdbCache)
+}

+ 104 - 0
vendor/github.com/fatedier/beego/cache/ssdb/ssdb_test.go

@@ -0,0 +1,104 @@
+package ssdb
+
+import (
+	"strconv"
+	"testing"
+	"time"
+
+	"github.com/astaxie/beego/cache"
+)
+
+func TestSsdbcacheCache(t *testing.T) {
+	ssdb, err := cache.NewCache("ssdb", `{"conn": "127.0.0.1:8888"}`)
+	if err != nil {
+		t.Error("init err")
+	}
+
+	// test put and exist
+	if ssdb.IsExist("ssdb") {
+		t.Error("check err")
+	}
+	timeoutDuration := 10 * time.Second
+	//timeoutDuration := -10*time.Second   if timeoutDuration is negtive,it means permanent
+	if err = ssdb.Put("ssdb", "ssdb", timeoutDuration); err != nil {
+		t.Error("set Error", err)
+	}
+	if !ssdb.IsExist("ssdb") {
+		t.Error("check err")
+	}
+
+	// Get test done
+	if err = ssdb.Put("ssdb", "ssdb", timeoutDuration); err != nil {
+		t.Error("set Error", err)
+	}
+
+	if v := ssdb.Get("ssdb"); v != "ssdb" {
+		t.Error("get Error")
+	}
+
+	//inc/dec test done
+	if err = ssdb.Put("ssdb", "2", timeoutDuration); err != nil {
+		t.Error("set Error", err)
+	}
+	if err = ssdb.Incr("ssdb"); err != nil {
+		t.Error("incr Error", err)
+	}
+
+	if v, err := strconv.Atoi(ssdb.Get("ssdb").(string)); err != nil || v != 3 {
+		t.Error("get err")
+	}
+
+	if err = ssdb.Decr("ssdb"); err != nil {
+		t.Error("decr error")
+	}
+
+	// test del
+	if err = ssdb.Put("ssdb", "3", timeoutDuration); err != nil {
+		t.Error("set Error", err)
+	}
+	if v, err := strconv.Atoi(ssdb.Get("ssdb").(string)); err != nil || v != 3 {
+		t.Error("get err")
+	}
+	if err := ssdb.Delete("ssdb"); err == nil {
+		if ssdb.IsExist("ssdb") {
+			t.Error("delete err")
+		}
+	}
+
+	//test string
+	if err = ssdb.Put("ssdb", "ssdb", -10*time.Second); err != nil {
+		t.Error("set Error", err)
+	}
+	if !ssdb.IsExist("ssdb") {
+		t.Error("check err")
+	}
+	if v := ssdb.Get("ssdb").(string); v != "ssdb" {
+		t.Error("get err")
+	}
+
+	//test GetMulti done
+	if err = ssdb.Put("ssdb1", "ssdb1", -10*time.Second); err != nil {
+		t.Error("set Error", err)
+	}
+	if !ssdb.IsExist("ssdb1") {
+		t.Error("check err")
+	}
+	vv := ssdb.GetMulti([]string{"ssdb", "ssdb1"})
+	if len(vv) != 2 {
+		t.Error("getmulti error")
+	}
+	if vv[0].(string) != "ssdb" {
+		t.Error("getmulti error")
+	}
+	if vv[1].(string) != "ssdb1" {
+		t.Error("getmulti error")
+	}
+
+	// test clear all done
+	if err = ssdb.ClearAll(); err != nil {
+		t.Error("clear all err")
+	}
+	if ssdb.IsExist("ssdb") || ssdb.IsExist("ssdb1") {
+		t.Error("check err")
+	}
+}

+ 489 - 0
vendor/github.com/fatedier/beego/config.go

@@ -0,0 +1,489 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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 beego
+
+import (
+	"fmt"
+	"os"
+	"path/filepath"
+	"reflect"
+	"runtime"
+	"strings"
+
+	"github.com/astaxie/beego/config"
+	"github.com/astaxie/beego/context"
+	"github.com/astaxie/beego/logs"
+	"github.com/astaxie/beego/session"
+	"github.com/astaxie/beego/utils"
+)
+
+// Config is the main struct for BConfig
+type Config struct {
+	AppName             string //Application name
+	RunMode             string //Running Mode: dev | prod
+	RouterCaseSensitive bool
+	ServerName          string
+	RecoverPanic        bool
+	RecoverFunc         func(*context.Context)
+	CopyRequestBody     bool
+	EnableGzip          bool
+	MaxMemory           int64
+	EnableErrorsShow    bool
+	EnableErrorsRender  bool
+	Listen              Listen
+	WebConfig           WebConfig
+	Log                 LogConfig
+}
+
+// Listen holds for http and https related config
+type Listen struct {
+	Graceful      bool // Graceful means use graceful module to start the server
+	ServerTimeOut int64
+	ListenTCP4    bool
+	EnableHTTP    bool
+	HTTPAddr      string
+	HTTPPort      int
+	EnableHTTPS   bool
+	HTTPSAddr     string
+	HTTPSPort     int
+	HTTPSCertFile string
+	HTTPSKeyFile  string
+	EnableAdmin   bool
+	AdminAddr     string
+	AdminPort     int
+	EnableFcgi    bool
+	EnableStdIo   bool // EnableStdIo works with EnableFcgi Use FCGI via standard I/O
+}
+
+// WebConfig holds web related config
+type WebConfig struct {
+	AutoRender             bool
+	EnableDocs             bool
+	FlashName              string
+	FlashSeparator         string
+	DirectoryIndex         bool
+	StaticDir              map[string]string
+	StaticExtensionsToGzip []string
+	TemplateLeft           string
+	TemplateRight          string
+	ViewsPath              string
+	EnableXSRF             bool
+	XSRFKey                string
+	XSRFExpire             int
+	Session                SessionConfig
+}
+
+// SessionConfig holds session related config
+type SessionConfig struct {
+	SessionOn                    bool
+	SessionProvider              string
+	SessionName                  string
+	SessionGCMaxLifetime         int64
+	SessionProviderConfig        string
+	SessionCookieLifeTime        int
+	SessionAutoSetCookie         bool
+	SessionDomain                string
+	SessionDisableHTTPOnly       bool // used to allow for cross domain cookies/javascript cookies.
+	SessionEnableSidInHTTPHeader bool //	enable store/get the sessionId into/from http headers
+	SessionNameInHTTPHeader      string
+	SessionEnableSidInURLQuery   bool //	enable get the sessionId from Url Query params
+}
+
+// LogConfig holds Log related config
+type LogConfig struct {
+	AccessLogs  bool
+	FileLineNum bool
+	Outputs     map[string]string // Store Adaptor : config
+}
+
+var (
+	// BConfig is the default config for Application
+	BConfig *Config
+	// AppConfig is the instance of Config, store the config information from file
+	AppConfig *beegoAppConfig
+	// AppPath is the absolute path to the app
+	AppPath string
+	// GlobalSessions is the instance for the session manager
+	GlobalSessions *session.Manager
+
+	// appConfigPath is the path to the config files
+	appConfigPath string
+	// appConfigProvider is the provider for the config, default is ini
+	appConfigProvider = "ini"
+)
+
+func init() {
+	BConfig = newBConfig()
+	var err error
+	if AppPath, err = filepath.Abs(filepath.Dir(os.Args[0])); err != nil {
+		panic(err)
+	}
+	workPath, err := os.Getwd()
+	if err != nil {
+		panic(err)
+	}
+	appConfigPath = filepath.Join(workPath, "conf", "app.conf")
+	if !utils.FileExists(appConfigPath) {
+		appConfigPath = filepath.Join(AppPath, "conf", "app.conf")
+		if !utils.FileExists(appConfigPath) {
+			AppConfig = &beegoAppConfig{innerConfig: config.NewFakeConfig()}
+			return
+		}
+	}
+	if err = parseConfig(appConfigPath); err != nil {
+		panic(err)
+	}
+}
+
+func recoverPanic(ctx *context.Context) {
+	if err := recover(); err != nil {
+		if err == ErrAbort {
+			return
+		}
+		if !BConfig.RecoverPanic {
+			panic(err)
+		}
+		if BConfig.EnableErrorsShow {
+			if _, ok := ErrorMaps[fmt.Sprint(err)]; ok {
+				exception(fmt.Sprint(err), ctx)
+				return
+			}
+		}
+		var stack string
+		logs.Critical("the request url is ", ctx.Input.URL())
+		logs.Critical("Handler crashed with error", err)
+		for i := 1; ; i++ {
+			_, file, line, ok := runtime.Caller(i)
+			if !ok {
+				break
+			}
+			logs.Critical(fmt.Sprintf("%s:%d", file, line))
+			stack = stack + fmt.Sprintln(fmt.Sprintf("%s:%d", file, line))
+		}
+		if BConfig.RunMode == DEV && BConfig.EnableErrorsRender {
+			showErr(err, ctx, stack)
+		}
+	}
+}
+
+func newBConfig() *Config {
+	return &Config{
+		AppName:             "beego",
+		RunMode:             DEV,
+		RouterCaseSensitive: true,
+		ServerName:          "beegoServer:" + VERSION,
+		RecoverPanic:        true,
+		RecoverFunc:         recoverPanic,
+		CopyRequestBody:     false,
+		EnableGzip:          false,
+		MaxMemory:           1 << 26, //64MB
+		EnableErrorsShow:    true,
+		EnableErrorsRender:  true,
+		Listen: Listen{
+			Graceful:      false,
+			ServerTimeOut: 0,
+			ListenTCP4:    false,
+			EnableHTTP:    true,
+			HTTPAddr:      "",
+			HTTPPort:      8080,
+			EnableHTTPS:   false,
+			HTTPSAddr:     "",
+			HTTPSPort:     10443,
+			HTTPSCertFile: "",
+			HTTPSKeyFile:  "",
+			EnableAdmin:   false,
+			AdminAddr:     "",
+			AdminPort:     8088,
+			EnableFcgi:    false,
+			EnableStdIo:   false,
+		},
+		WebConfig: WebConfig{
+			AutoRender:             true,
+			EnableDocs:             false,
+			FlashName:              "BEEGO_FLASH",
+			FlashSeparator:         "BEEGOFLASH",
+			DirectoryIndex:         false,
+			StaticDir:              map[string]string{"/static": "static"},
+			StaticExtensionsToGzip: []string{".css", ".js"},
+			TemplateLeft:           "{{",
+			TemplateRight:          "}}",
+			ViewsPath:              "views",
+			EnableXSRF:             false,
+			XSRFKey:                "beegoxsrf",
+			XSRFExpire:             0,
+			Session: SessionConfig{
+				SessionOn:                    false,
+				SessionProvider:              "memory",
+				SessionName:                  "beegosessionID",
+				SessionGCMaxLifetime:         3600,
+				SessionProviderConfig:        "",
+				SessionDisableHTTPOnly:       false,
+				SessionCookieLifeTime:        0, //set cookie default is the browser life
+				SessionAutoSetCookie:         true,
+				SessionDomain:                "",
+				SessionEnableSidInHTTPHeader: false, //	enable store/get the sessionId into/from http headers
+				SessionNameInHTTPHeader:      "Beegosessionid",
+				SessionEnableSidInURLQuery:   false, //	enable get the sessionId from Url Query params
+			},
+		},
+		Log: LogConfig{
+			AccessLogs:  false,
+			FileLineNum: true,
+			Outputs:     map[string]string{"console": ""},
+		},
+	}
+}
+
+// now only support ini, next will support json.
+func parseConfig(appConfigPath string) (err error) {
+	AppConfig, err = newAppConfig(appConfigProvider, appConfigPath)
+	if err != nil {
+		return err
+	}
+	return assignConfig(AppConfig)
+}
+
+func assignConfig(ac config.Configer) error {
+	for _, i := range []interface{}{BConfig, &BConfig.Listen, &BConfig.WebConfig, &BConfig.Log, &BConfig.WebConfig.Session} {
+		assignSingleConfig(i, ac)
+	}
+	// set the run mode first
+	if envRunMode := os.Getenv("BEEGO_RUNMODE"); envRunMode != "" {
+		BConfig.RunMode = envRunMode
+	} else if runMode := ac.String("RunMode"); runMode != "" {
+		BConfig.RunMode = runMode
+	}
+
+	if sd := ac.String("StaticDir"); sd != "" {
+		BConfig.WebConfig.StaticDir = map[string]string{}
+		sds := strings.Fields(sd)
+		for _, v := range sds {
+			if url2fsmap := strings.SplitN(v, ":", 2); len(url2fsmap) == 2 {
+				BConfig.WebConfig.StaticDir["/"+strings.Trim(url2fsmap[0], "/")] = url2fsmap[1]
+			} else {
+				BConfig.WebConfig.StaticDir["/"+strings.Trim(url2fsmap[0], "/")] = url2fsmap[0]
+			}
+		}
+	}
+
+	if sgz := ac.String("StaticExtensionsToGzip"); sgz != "" {
+		extensions := strings.Split(sgz, ",")
+		fileExts := []string{}
+		for _, ext := range extensions {
+			ext = strings.TrimSpace(ext)
+			if ext == "" {
+				continue
+			}
+			if !strings.HasPrefix(ext, ".") {
+				ext = "." + ext
+			}
+			fileExts = append(fileExts, ext)
+		}
+		if len(fileExts) > 0 {
+			BConfig.WebConfig.StaticExtensionsToGzip = fileExts
+		}
+	}
+
+	if lo := ac.String("LogOutputs"); lo != "" {
+		// if lo is not nil or empty
+		// means user has set his own LogOutputs
+		// clear the default setting to BConfig.Log.Outputs
+		BConfig.Log.Outputs = make(map[string]string)
+		los := strings.Split(lo, ";")
+		for _, v := range los {
+			if logType2Config := strings.SplitN(v, ",", 2); len(logType2Config) == 2 {
+				BConfig.Log.Outputs[logType2Config[0]] = logType2Config[1]
+			} else {
+				continue
+			}
+		}
+	}
+
+	//init log
+	logs.Reset()
+	for adaptor, config := range BConfig.Log.Outputs {
+		err := logs.SetLogger(adaptor, config)
+		if err != nil {
+			fmt.Fprintln(os.Stderr, fmt.Sprintf("%s with the config %q got err:%s", adaptor, config, err.Error()))
+		}
+	}
+	logs.SetLogFuncCall(BConfig.Log.FileLineNum)
+
+	return nil
+}
+
+func assignSingleConfig(p interface{}, ac config.Configer) {
+	pt := reflect.TypeOf(p)
+	if pt.Kind() != reflect.Ptr {
+		return
+	}
+	pt = pt.Elem()
+	if pt.Kind() != reflect.Struct {
+		return
+	}
+	pv := reflect.ValueOf(p).Elem()
+
+	for i := 0; i < pt.NumField(); i++ {
+		pf := pv.Field(i)
+		if !pf.CanSet() {
+			continue
+		}
+		name := pt.Field(i).Name
+		switch pf.Kind() {
+		case reflect.String:
+			pf.SetString(ac.DefaultString(name, pf.String()))
+		case reflect.Int, reflect.Int64:
+			pf.SetInt(int64(ac.DefaultInt64(name, pf.Int())))
+		case reflect.Bool:
+			pf.SetBool(ac.DefaultBool(name, pf.Bool()))
+		case reflect.Struct:
+		default:
+			//do nothing here
+		}
+	}
+
+}
+
+// LoadAppConfig allow developer to apply a config file
+func LoadAppConfig(adapterName, configPath string) error {
+	absConfigPath, err := filepath.Abs(configPath)
+	if err != nil {
+		return err
+	}
+
+	if !utils.FileExists(absConfigPath) {
+		return fmt.Errorf("the target config file: %s don't exist", configPath)
+	}
+
+	appConfigPath = absConfigPath
+	appConfigProvider = adapterName
+
+	return parseConfig(appConfigPath)
+}
+
+type beegoAppConfig struct {
+	innerConfig config.Configer
+}
+
+func newAppConfig(appConfigProvider, appConfigPath string) (*beegoAppConfig, error) {
+	ac, err := config.NewConfig(appConfigProvider, appConfigPath)
+	if err != nil {
+		return nil, err
+	}
+	return &beegoAppConfig{ac}, nil
+}
+
+func (b *beegoAppConfig) Set(key, val string) error {
+	if err := b.innerConfig.Set(BConfig.RunMode+"::"+key, val); err != nil {
+		return err
+	}
+	return b.innerConfig.Set(key, val)
+}
+
+func (b *beegoAppConfig) String(key string) string {
+	if v := b.innerConfig.String(BConfig.RunMode + "::" + key); v != "" {
+		return v
+	}
+	return b.innerConfig.String(key)
+}
+
+func (b *beegoAppConfig) Strings(key string) []string {
+	if v := b.innerConfig.Strings(BConfig.RunMode + "::" + key); len(v) > 0 {
+		return v
+	}
+	return b.innerConfig.Strings(key)
+}
+
+func (b *beegoAppConfig) Int(key string) (int, error) {
+	if v, err := b.innerConfig.Int(BConfig.RunMode + "::" + key); err == nil {
+		return v, nil
+	}
+	return b.innerConfig.Int(key)
+}
+
+func (b *beegoAppConfig) Int64(key string) (int64, error) {
+	if v, err := b.innerConfig.Int64(BConfig.RunMode + "::" + key); err == nil {
+		return v, nil
+	}
+	return b.innerConfig.Int64(key)
+}
+
+func (b *beegoAppConfig) Bool(key string) (bool, error) {
+	if v, err := b.innerConfig.Bool(BConfig.RunMode + "::" + key); err == nil {
+		return v, nil
+	}
+	return b.innerConfig.Bool(key)
+}
+
+func (b *beegoAppConfig) Float(key string) (float64, error) {
+	if v, err := b.innerConfig.Float(BConfig.RunMode + "::" + key); err == nil {
+		return v, nil
+	}
+	return b.innerConfig.Float(key)
+}
+
+func (b *beegoAppConfig) DefaultString(key string, defaultVal string) string {
+	if v := b.String(key); v != "" {
+		return v
+	}
+	return defaultVal
+}
+
+func (b *beegoAppConfig) DefaultStrings(key string, defaultVal []string) []string {
+	if v := b.Strings(key); len(v) != 0 {
+		return v
+	}
+	return defaultVal
+}
+
+func (b *beegoAppConfig) DefaultInt(key string, defaultVal int) int {
+	if v, err := b.Int(key); err == nil {
+		return v
+	}
+	return defaultVal
+}
+
+func (b *beegoAppConfig) DefaultInt64(key string, defaultVal int64) int64 {
+	if v, err := b.Int64(key); err == nil {
+		return v
+	}
+	return defaultVal
+}
+
+func (b *beegoAppConfig) DefaultBool(key string, defaultVal bool) bool {
+	if v, err := b.Bool(key); err == nil {
+		return v
+	}
+	return defaultVal
+}
+
+func (b *beegoAppConfig) DefaultFloat(key string, defaultVal float64) float64 {
+	if v, err := b.Float(key); err == nil {
+		return v
+	}
+	return defaultVal
+}
+
+func (b *beegoAppConfig) DIY(key string) (interface{}, error) {
+	return b.innerConfig.DIY(key)
+}
+
+func (b *beegoAppConfig) GetSection(section string) (map[string]string, error) {
+	return b.innerConfig.GetSection(section)
+}
+
+func (b *beegoAppConfig) SaveConfigFile(filename string) error {
+	return b.innerConfig.SaveConfigFile(filename)
+}

+ 242 - 0
vendor/github.com/fatedier/beego/config/config.go

@@ -0,0 +1,242 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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 config is used to parse config.
+// Usage:
+//  import "github.com/astaxie/beego/config"
+//Examples.
+//
+//  cnf, err := config.NewConfig("ini", "config.conf")
+//
+//  cnf APIS:
+//
+//  cnf.Set(key, val string) error
+//  cnf.String(key string) string
+//  cnf.Strings(key string) []string
+//  cnf.Int(key string) (int, error)
+//  cnf.Int64(key string) (int64, error)
+//  cnf.Bool(key string) (bool, error)
+//  cnf.Float(key string) (float64, error)
+//  cnf.DefaultString(key string, defaultVal string) string
+//  cnf.DefaultStrings(key string, defaultVal []string) []string
+//  cnf.DefaultInt(key string, defaultVal int) int
+//  cnf.DefaultInt64(key string, defaultVal int64) int64
+//  cnf.DefaultBool(key string, defaultVal bool) bool
+//  cnf.DefaultFloat(key string, defaultVal float64) float64
+//  cnf.DIY(key string) (interface{}, error)
+//  cnf.GetSection(section string) (map[string]string, error)
+//  cnf.SaveConfigFile(filename string) error
+//More docs http://beego.me/docs/module/config.md
+package config
+
+import (
+	"fmt"
+	"os"
+	"reflect"
+	"time"
+)
+
+// Configer defines how to get and set value from configuration raw data.
+type Configer interface {
+	Set(key, val string) error   //support section::key type in given key when using ini type.
+	String(key string) string    //support section::key type in key string when using ini and json type; Int,Int64,Bool,Float,DIY are same.
+	Strings(key string) []string //get string slice
+	Int(key string) (int, error)
+	Int64(key string) (int64, error)
+	Bool(key string) (bool, error)
+	Float(key string) (float64, error)
+	DefaultString(key string, defaultVal string) string      // support section::key type in key string when using ini and json type; Int,Int64,Bool,Float,DIY are same.
+	DefaultStrings(key string, defaultVal []string) []string //get string slice
+	DefaultInt(key string, defaultVal int) int
+	DefaultInt64(key string, defaultVal int64) int64
+	DefaultBool(key string, defaultVal bool) bool
+	DefaultFloat(key string, defaultVal float64) float64
+	DIY(key string) (interface{}, error)
+	GetSection(section string) (map[string]string, error)
+	SaveConfigFile(filename string) error
+}
+
+// Config is the adapter interface for parsing config file to get raw data to Configer.
+type Config interface {
+	Parse(key string) (Configer, error)
+	ParseData(data []byte) (Configer, error)
+}
+
+var adapters = make(map[string]Config)
+
+// Register makes a config adapter available by the adapter name.
+// If Register is called twice with the same name or if driver is nil,
+// it panics.
+func Register(name string, adapter Config) {
+	if adapter == nil {
+		panic("config: Register adapter is nil")
+	}
+	if _, ok := adapters[name]; ok {
+		panic("config: Register called twice for adapter " + name)
+	}
+	adapters[name] = adapter
+}
+
+// NewConfig adapterName is ini/json/xml/yaml.
+// filename is the config file path.
+func NewConfig(adapterName, filename string) (Configer, error) {
+	adapter, ok := adapters[adapterName]
+	if !ok {
+		return nil, fmt.Errorf("config: unknown adaptername %q (forgotten import?)", adapterName)
+	}
+	return adapter.Parse(filename)
+}
+
+// NewConfigData adapterName is ini/json/xml/yaml.
+// data is the config data.
+func NewConfigData(adapterName string, data []byte) (Configer, error) {
+	adapter, ok := adapters[adapterName]
+	if !ok {
+		return nil, fmt.Errorf("config: unknown adaptername %q (forgotten import?)", adapterName)
+	}
+	return adapter.ParseData(data)
+}
+
+// ExpandValueEnvForMap convert all string value with environment variable.
+func ExpandValueEnvForMap(m map[string]interface{}) map[string]interface{} {
+	for k, v := range m {
+		switch value := v.(type) {
+		case string:
+			m[k] = ExpandValueEnv(value)
+		case map[string]interface{}:
+			m[k] = ExpandValueEnvForMap(value)
+		case map[string]string:
+			for k2, v2 := range value {
+				value[k2] = ExpandValueEnv(v2)
+			}
+			m[k] = value
+		}
+	}
+	return m
+}
+
+// ExpandValueEnv returns value of convert with environment variable.
+//
+// Return environment variable if value start with "${" and end with "}".
+// Return default value if environment variable is empty or not exist.
+//
+// It accept value formats "${env}" , "${env||}}" , "${env||defaultValue}" , "defaultvalue".
+// Examples:
+//	v1 := config.ExpandValueEnv("${GOPATH}")			// return the GOPATH environment variable.
+//	v2 := config.ExpandValueEnv("${GOAsta||/usr/local/go}")	// return the default value "/usr/local/go/".
+//	v3 := config.ExpandValueEnv("Astaxie")				// return the value "Astaxie".
+func ExpandValueEnv(value string) (realValue string) {
+	realValue = value
+
+	vLen := len(value)
+	// 3 = ${}
+	if vLen < 3 {
+		return
+	}
+	// Need start with "${" and end with "}", then return.
+	if value[0] != '$' || value[1] != '{' || value[vLen-1] != '}' {
+		return
+	}
+
+	key := ""
+	defalutV := ""
+	// value start with "${"
+	for i := 2; i < vLen; i++ {
+		if value[i] == '|' && (i+1 < vLen && value[i+1] == '|') {
+			key = value[2:i]
+			defalutV = value[i+2 : vLen-1] // other string is default value.
+			break
+		} else if value[i] == '}' {
+			key = value[2:i]
+			break
+		}
+	}
+
+	realValue = os.Getenv(key)
+	if realValue == "" {
+		realValue = defalutV
+	}
+
+	return
+}
+
+// ParseBool returns the boolean value represented by the string.
+//
+// It accepts 1, 1.0, t, T, TRUE, true, True, YES, yes, Yes,Y, y, ON, on, On,
+// 0, 0.0, f, F, FALSE, false, False, NO, no, No, N,n, OFF, off, Off.
+// Any other value returns an error.
+func ParseBool(val interface{}) (value bool, err error) {
+	if val != nil {
+		switch v := val.(type) {
+		case bool:
+			return v, nil
+		case string:
+			switch v {
+			case "1", "t", "T", "true", "TRUE", "True", "YES", "yes", "Yes", "Y", "y", "ON", "on", "On":
+				return true, nil
+			case "0", "f", "F", "false", "FALSE", "False", "NO", "no", "No", "N", "n", "OFF", "off", "Off":
+				return false, nil
+			}
+		case int8, int32, int64:
+			strV := fmt.Sprintf("%s", v)
+			if strV == "1" {
+				return true, nil
+			} else if strV == "0" {
+				return false, nil
+			}
+		case float64:
+			if v == 1 {
+				return true, nil
+			} else if v == 0 {
+				return false, nil
+			}
+		}
+		return false, fmt.Errorf("parsing %q: invalid syntax", val)
+	}
+	return false, fmt.Errorf("parsing <nil>: invalid syntax")
+}
+
+// ToString converts values of any type to string.
+func ToString(x interface{}) string {
+	switch y := x.(type) {
+
+	// Handle dates with special logic
+	// This needs to come above the fmt.Stringer
+	// test since time.Time's have a .String()
+	// method
+	case time.Time:
+		return y.Format("A Monday")
+
+	// Handle type string
+	case string:
+		return y
+
+	// Handle type with .String() method
+	case fmt.Stringer:
+		return y.String()
+
+	// Handle type with .Error() method
+	case error:
+		return y.Error()
+
+	}
+
+	// Handle named string type
+	if v := reflect.ValueOf(x); v.Kind() == reflect.String {
+		return v.String()
+	}
+
+	// Fallback to fmt package for anything else like numeric types
+	return fmt.Sprint(x)
+}

+ 55 - 0
vendor/github.com/fatedier/beego/config/config_test.go

@@ -0,0 +1,55 @@
+// Copyright 2016 beego Author. All Rights Reserved.
+//
+// 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 config
+
+import (
+	"os"
+	"testing"
+)
+
+func TestExpandValueEnv(t *testing.T) {
+
+	testCases := []struct {
+		item string
+		want string
+	}{
+		{"", ""},
+		{"$", "$"},
+		{"{", "{"},
+		{"{}", "{}"},
+		{"${}", ""},
+		{"${|}", ""},
+		{"${}", ""},
+		{"${{}}", ""},
+		{"${{||}}", "}"},
+		{"${pwd||}", ""},
+		{"${pwd||}", ""},
+		{"${pwd||}", ""},
+		{"${pwd||}}", "}"},
+		{"${pwd||{{||}}}", "{{||}}"},
+		{"${GOPATH}", os.Getenv("GOPATH")},
+		{"${GOPATH||}", os.Getenv("GOPATH")},
+		{"${GOPATH||root}", os.Getenv("GOPATH")},
+		{"${GOPATH_NOT||root}", "root"},
+		{"${GOPATH_NOT||||root}", "||root"},
+	}
+
+	for _, c := range testCases {
+		if got := ExpandValueEnv(c.item); got != c.want {
+			t.Errorf("expand value error, item %q want %q, got %q", c.item, c.want, got)
+		}
+	}
+
+}

+ 85 - 0
vendor/github.com/fatedier/beego/config/env/env.go

@@ -0,0 +1,85 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+// Copyright 2017 Faissal Elamraoui. All Rights Reserved.
+//
+// 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 env
+
+import (
+	"fmt"
+	"os"
+	"strings"
+
+	"github.com/astaxie/beego/utils"
+)
+
+var env *utils.BeeMap
+
+func init() {
+	env = utils.NewBeeMap()
+	for _, e := range os.Environ() {
+		splits := strings.Split(e, "=")
+		env.Set(splits[0], os.Getenv(splits[0]))
+	}
+}
+
+// Get returns a value by key.
+// If the key does not exist, the default value will be returned.
+func Get(key string, defVal string) string {
+	if val := env.Get(key); val != nil {
+		return val.(string)
+	}
+	return defVal
+}
+
+// MustGet returns a value by key.
+// If the key does not exist, it will return an error.
+func MustGet(key string) (string, error) {
+	if val := env.Get(key); val != nil {
+		return val.(string), nil
+	}
+	return "", fmt.Errorf("no env variable with %s", key)
+}
+
+// Set sets a value in the ENV copy.
+// This does not affect the child process environment.
+func Set(key string, value string) {
+	env.Set(key, value)
+}
+
+// MustSet sets a value in the ENV copy and the child process environment.
+// It returns an error in case the set operation failed.
+func MustSet(key string, value string) error {
+	err := os.Setenv(key, value)
+	if err != nil {
+		return err
+	}
+	env.Set(key, value)
+	return nil
+}
+
+// GetAll returns all keys/values in the current child process environment.
+func GetAll() map[string]string {
+	items := env.Items()
+	envs := make(map[string]string, env.Count())
+
+	for key, val := range items {
+		switch key := key.(type) {
+		case string:
+			switch val := val.(type) {
+			case string:
+				envs[key] = val
+			}
+		}
+	}
+	return envs
+}

+ 75 - 0
vendor/github.com/fatedier/beego/config/env/env_test.go

@@ -0,0 +1,75 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+// Copyright 2017 Faissal Elamraoui. All Rights Reserved.
+//
+// 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 env
+
+import (
+	"os"
+	"testing"
+)
+
+func TestEnvGet(t *testing.T) {
+	gopath := Get("GOPATH", "")
+	if gopath != os.Getenv("GOPATH") {
+		t.Error("expected GOPATH not empty.")
+	}
+
+	noExistVar := Get("NOEXISTVAR", "foo")
+	if noExistVar != "foo" {
+		t.Errorf("expected NOEXISTVAR to equal foo, got %s.", noExistVar)
+	}
+}
+
+func TestEnvMustGet(t *testing.T) {
+	gopath, err := MustGet("GOPATH")
+	if err != nil {
+		t.Error(err)
+	}
+
+	if gopath != os.Getenv("GOPATH") {
+		t.Errorf("expected GOPATH to be the same, got %s.", gopath)
+	}
+
+	_, err = MustGet("NOEXISTVAR")
+	if err == nil {
+		t.Error("expected error to be non-nil")
+	}
+}
+
+func TestEnvSet(t *testing.T) {
+	Set("MYVAR", "foo")
+	myVar := Get("MYVAR", "bar")
+	if myVar != "foo" {
+		t.Errorf("expected MYVAR to equal foo, got %s.", myVar)
+	}
+}
+
+func TestEnvMustSet(t *testing.T) {
+	err := MustSet("FOO", "bar")
+	if err != nil {
+		t.Error(err)
+	}
+
+	fooVar := os.Getenv("FOO")
+	if fooVar != "bar" {
+		t.Errorf("expected FOO variable to equal bar, got %s.", fooVar)
+	}
+}
+
+func TestEnvGetAll(t *testing.T) {
+	envMap := GetAll()
+	if len(envMap) == 0 {
+		t.Error("expected environment not empty.")
+	}
+}

+ 134 - 0
vendor/github.com/fatedier/beego/config/fake.go

@@ -0,0 +1,134 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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 config
+
+import (
+	"errors"
+	"strconv"
+	"strings"
+)
+
+type fakeConfigContainer struct {
+	data map[string]string
+}
+
+func (c *fakeConfigContainer) getData(key string) string {
+	return c.data[strings.ToLower(key)]
+}
+
+func (c *fakeConfigContainer) Set(key, val string) error {
+	c.data[strings.ToLower(key)] = val
+	return nil
+}
+
+func (c *fakeConfigContainer) String(key string) string {
+	return c.getData(key)
+}
+
+func (c *fakeConfigContainer) DefaultString(key string, defaultval string) string {
+	v := c.String(key)
+	if v == "" {
+		return defaultval
+	}
+	return v
+}
+
+func (c *fakeConfigContainer) Strings(key string) []string {
+	v := c.String(key)
+	if v == "" {
+		return nil
+	}
+	return strings.Split(v, ";")
+}
+
+func (c *fakeConfigContainer) DefaultStrings(key string, defaultval []string) []string {
+	v := c.Strings(key)
+	if v == nil {
+		return defaultval
+	}
+	return v
+}
+
+func (c *fakeConfigContainer) Int(key string) (int, error) {
+	return strconv.Atoi(c.getData(key))
+}
+
+func (c *fakeConfigContainer) DefaultInt(key string, defaultval int) int {
+	v, err := c.Int(key)
+	if err != nil {
+		return defaultval
+	}
+	return v
+}
+
+func (c *fakeConfigContainer) Int64(key string) (int64, error) {
+	return strconv.ParseInt(c.getData(key), 10, 64)
+}
+
+func (c *fakeConfigContainer) DefaultInt64(key string, defaultval int64) int64 {
+	v, err := c.Int64(key)
+	if err != nil {
+		return defaultval
+	}
+	return v
+}
+
+func (c *fakeConfigContainer) Bool(key string) (bool, error) {
+	return ParseBool(c.getData(key))
+}
+
+func (c *fakeConfigContainer) DefaultBool(key string, defaultval bool) bool {
+	v, err := c.Bool(key)
+	if err != nil {
+		return defaultval
+	}
+	return v
+}
+
+func (c *fakeConfigContainer) Float(key string) (float64, error) {
+	return strconv.ParseFloat(c.getData(key), 64)
+}
+
+func (c *fakeConfigContainer) DefaultFloat(key string, defaultval float64) float64 {
+	v, err := c.Float(key)
+	if err != nil {
+		return defaultval
+	}
+	return v
+}
+
+func (c *fakeConfigContainer) DIY(key string) (interface{}, error) {
+	if v, ok := c.data[strings.ToLower(key)]; ok {
+		return v, nil
+	}
+	return nil, errors.New("key not find")
+}
+
+func (c *fakeConfigContainer) GetSection(section string) (map[string]string, error) {
+	return nil, errors.New("not implement in the fakeConfigContainer")
+}
+
+func (c *fakeConfigContainer) SaveConfigFile(filename string) error {
+	return errors.New("not implement in the fakeConfigContainer")
+}
+
+var _ Configer = new(fakeConfigContainer)
+
+// NewFakeConfig return a fake Congiger
+func NewFakeConfig() Configer {
+	return &fakeConfigContainer{
+		data: make(map[string]string),
+	}
+}

+ 474 - 0
vendor/github.com/fatedier/beego/config/ini.go

@@ -0,0 +1,474 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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 config
+
+import (
+	"bufio"
+	"bytes"
+	"errors"
+	"io"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"strconv"
+	"strings"
+	"sync"
+)
+
+var (
+	defaultSection = "default"   // default section means if some ini items not in a section, make them in default section,
+	bNumComment    = []byte{'#'} // number signal
+	bSemComment    = []byte{';'} // semicolon signal
+	bEmpty         = []byte{}
+	bEqual         = []byte{'='} // equal signal
+	bDQuote        = []byte{'"'} // quote signal
+	sectionStart   = []byte{'['} // section start signal
+	sectionEnd     = []byte{']'} // section end signal
+	lineBreak      = "\n"
+)
+
+// IniConfig implements Config to parse ini file.
+type IniConfig struct {
+}
+
+// Parse creates a new Config and parses the file configuration from the named file.
+func (ini *IniConfig) Parse(name string) (Configer, error) {
+	return ini.parseFile(name)
+}
+
+func (ini *IniConfig) parseFile(name string) (*IniConfigContainer, error) {
+	data, err := ioutil.ReadFile(name)
+	if err != nil {
+		return nil, err
+	}
+
+	return ini.parseData(filepath.Dir(name), data)
+}
+
+func (ini *IniConfig) parseData(dir string, data []byte) (*IniConfigContainer, error) {
+	cfg := &IniConfigContainer{
+		data:           make(map[string]map[string]string),
+		sectionComment: make(map[string]string),
+		keyComment:     make(map[string]string),
+		RWMutex:        sync.RWMutex{},
+	}
+	cfg.Lock()
+	defer cfg.Unlock()
+
+	var comment bytes.Buffer
+	buf := bufio.NewReader(bytes.NewBuffer(data))
+	// check the BOM
+	head, err := buf.Peek(3)
+	if err == nil && head[0] == 239 && head[1] == 187 && head[2] == 191 {
+		for i := 1; i <= 3; i++ {
+			buf.ReadByte()
+		}
+	}
+	section := defaultSection
+	for {
+		line, _, err := buf.ReadLine()
+		if err == io.EOF {
+			break
+		}
+		//It might be a good idea to throw a error on all unknonw errors?
+		if _, ok := err.(*os.PathError); ok {
+			return nil, err
+		}
+		line = bytes.TrimSpace(line)
+		if bytes.Equal(line, bEmpty) {
+			continue
+		}
+		var bComment []byte
+		switch {
+		case bytes.HasPrefix(line, bNumComment):
+			bComment = bNumComment
+		case bytes.HasPrefix(line, bSemComment):
+			bComment = bSemComment
+		}
+		if bComment != nil {
+			line = bytes.TrimLeft(line, string(bComment))
+			// Need append to a new line if multi-line comments.
+			if comment.Len() > 0 {
+				comment.WriteByte('\n')
+			}
+			comment.Write(line)
+			continue
+		}
+
+		if bytes.HasPrefix(line, sectionStart) && bytes.HasSuffix(line, sectionEnd) {
+			section = strings.ToLower(string(line[1 : len(line)-1])) // section name case insensitive
+			if comment.Len() > 0 {
+				cfg.sectionComment[section] = comment.String()
+				comment.Reset()
+			}
+			if _, ok := cfg.data[section]; !ok {
+				cfg.data[section] = make(map[string]string)
+			}
+			continue
+		}
+
+		if _, ok := cfg.data[section]; !ok {
+			cfg.data[section] = make(map[string]string)
+		}
+		keyValue := bytes.SplitN(line, bEqual, 2)
+
+		key := string(bytes.TrimSpace(keyValue[0])) // key name case insensitive
+		key = strings.ToLower(key)
+
+		// handle include "other.conf"
+		if len(keyValue) == 1 && strings.HasPrefix(key, "include") {
+
+			includefiles := strings.Fields(key)
+			if includefiles[0] == "include" && len(includefiles) == 2 {
+
+				otherfile := strings.Trim(includefiles[1], "\"")
+				if !filepath.IsAbs(otherfile) {
+					otherfile = filepath.Join(dir, otherfile)
+				}
+
+				i, err := ini.parseFile(otherfile)
+				if err != nil {
+					return nil, err
+				}
+
+				for sec, dt := range i.data {
+					if _, ok := cfg.data[sec]; !ok {
+						cfg.data[sec] = make(map[string]string)
+					}
+					for k, v := range dt {
+						cfg.data[sec][k] = v
+					}
+				}
+
+				for sec, comm := range i.sectionComment {
+					cfg.sectionComment[sec] = comm
+				}
+
+				for k, comm := range i.keyComment {
+					cfg.keyComment[k] = comm
+				}
+
+				continue
+			}
+		}
+
+		if len(keyValue) != 2 {
+			return nil, errors.New("read the content error: \"" + string(line) + "\", should key = val")
+		}
+		val := bytes.TrimSpace(keyValue[1])
+		if bytes.HasPrefix(val, bDQuote) {
+			val = bytes.Trim(val, `"`)
+		}
+
+		cfg.data[section][key] = ExpandValueEnv(string(val))
+		if comment.Len() > 0 {
+			cfg.keyComment[section+"."+key] = comment.String()
+			comment.Reset()
+		}
+
+	}
+	return cfg, nil
+}
+
+// ParseData parse ini the data
+// When include other.conf,other.conf is either absolute directory
+// or under beego in default temporary directory(/tmp/beego).
+func (ini *IniConfig) ParseData(data []byte) (Configer, error) {
+	dir := filepath.Join(os.TempDir(), "beego")
+	os.MkdirAll(dir, os.ModePerm)
+
+	return ini.parseData(dir, data)
+}
+
+// IniConfigContainer A Config represents the ini configuration.
+// When set and get value, support key as section:name type.
+type IniConfigContainer struct {
+	data           map[string]map[string]string // section=> key:val
+	sectionComment map[string]string            // section : comment
+	keyComment     map[string]string            // id: []{comment, key...}; id 1 is for main comment.
+	sync.RWMutex
+}
+
+// Bool returns the boolean value for a given key.
+func (c *IniConfigContainer) Bool(key string) (bool, error) {
+	return ParseBool(c.getdata(key))
+}
+
+// DefaultBool returns the boolean value for a given key.
+// if err != nil return defaltval
+func (c *IniConfigContainer) DefaultBool(key string, defaultval bool) bool {
+	v, err := c.Bool(key)
+	if err != nil {
+		return defaultval
+	}
+	return v
+}
+
+// Int returns the integer value for a given key.
+func (c *IniConfigContainer) Int(key string) (int, error) {
+	return strconv.Atoi(c.getdata(key))
+}
+
+// DefaultInt returns the integer value for a given key.
+// if err != nil return defaltval
+func (c *IniConfigContainer) DefaultInt(key string, defaultval int) int {
+	v, err := c.Int(key)
+	if err != nil {
+		return defaultval
+	}
+	return v
+}
+
+// Int64 returns the int64 value for a given key.
+func (c *IniConfigContainer) Int64(key string) (int64, error) {
+	return strconv.ParseInt(c.getdata(key), 10, 64)
+}
+
+// DefaultInt64 returns the int64 value for a given key.
+// if err != nil return defaltval
+func (c *IniConfigContainer) DefaultInt64(key string, defaultval int64) int64 {
+	v, err := c.Int64(key)
+	if err != nil {
+		return defaultval
+	}
+	return v
+}
+
+// Float returns the float value for a given key.
+func (c *IniConfigContainer) Float(key string) (float64, error) {
+	return strconv.ParseFloat(c.getdata(key), 64)
+}
+
+// DefaultFloat returns the float64 value for a given key.
+// if err != nil return defaltval
+func (c *IniConfigContainer) DefaultFloat(key string, defaultval float64) float64 {
+	v, err := c.Float(key)
+	if err != nil {
+		return defaultval
+	}
+	return v
+}
+
+// String returns the string value for a given key.
+func (c *IniConfigContainer) String(key string) string {
+	return c.getdata(key)
+}
+
+// DefaultString returns the string value for a given key.
+// if err != nil return defaltval
+func (c *IniConfigContainer) DefaultString(key string, defaultval string) string {
+	v := c.String(key)
+	if v == "" {
+		return defaultval
+	}
+	return v
+}
+
+// Strings returns the []string value for a given key.
+// Return nil if config value does not exist or is empty.
+func (c *IniConfigContainer) Strings(key string) []string {
+	v := c.String(key)
+	if v == "" {
+		return nil
+	}
+	return strings.Split(v, ";")
+}
+
+// DefaultStrings returns the []string value for a given key.
+// if err != nil return defaltval
+func (c *IniConfigContainer) DefaultStrings(key string, defaultval []string) []string {
+	v := c.Strings(key)
+	if v == nil {
+		return defaultval
+	}
+	return v
+}
+
+// GetSection returns map for the given section
+func (c *IniConfigContainer) GetSection(section string) (map[string]string, error) {
+	if v, ok := c.data[section]; ok {
+		return v, nil
+	}
+	return nil, errors.New("not exist section")
+}
+
+// SaveConfigFile save the config into file.
+//
+// BUG(env): The environment variable config item will be saved with real value in SaveConfigFile Funcation.
+func (c *IniConfigContainer) SaveConfigFile(filename string) (err error) {
+	// Write configuration file by filename.
+	f, err := os.Create(filename)
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+
+	// Get section or key comments. Fixed #1607
+	getCommentStr := func(section, key string) string {
+		comment, ok := "", false
+		if len(key) == 0 {
+			comment, ok = c.sectionComment[section]
+		} else {
+			comment, ok = c.keyComment[section+"."+key]
+		}
+
+		if ok {
+			// Empty comment
+			if len(comment) == 0 || len(strings.TrimSpace(comment)) == 0 {
+				return string(bNumComment)
+			}
+			prefix := string(bNumComment)
+			// Add the line head character "#"
+			return prefix + strings.Replace(comment, lineBreak, lineBreak+prefix, -1)
+		}
+		return ""
+	}
+
+	buf := bytes.NewBuffer(nil)
+	// Save default section at first place
+	if dt, ok := c.data[defaultSection]; ok {
+		for key, val := range dt {
+			if key != " " {
+				// Write key comments.
+				if v := getCommentStr(defaultSection, key); len(v) > 0 {
+					if _, err = buf.WriteString(v + lineBreak); err != nil {
+						return err
+					}
+				}
+
+				// Write key and value.
+				if _, err = buf.WriteString(key + string(bEqual) + val + lineBreak); err != nil {
+					return err
+				}
+			}
+		}
+
+		// Put a line between sections.
+		if _, err = buf.WriteString(lineBreak); err != nil {
+			return err
+		}
+	}
+	// Save named sections
+	for section, dt := range c.data {
+		if section != defaultSection {
+			// Write section comments.
+			if v := getCommentStr(section, ""); len(v) > 0 {
+				if _, err = buf.WriteString(v + lineBreak); err != nil {
+					return err
+				}
+			}
+
+			// Write section name.
+			if _, err = buf.WriteString(string(sectionStart) + section + string(sectionEnd) + lineBreak); err != nil {
+				return err
+			}
+
+			for key, val := range dt {
+				if key != " " {
+					// Write key comments.
+					if v := getCommentStr(section, key); len(v) > 0 {
+						if _, err = buf.WriteString(v + lineBreak); err != nil {
+							return err
+						}
+					}
+
+					// Write key and value.
+					if _, err = buf.WriteString(key + string(bEqual) + val + lineBreak); err != nil {
+						return err
+					}
+				}
+			}
+
+			// Put a line between sections.
+			if _, err = buf.WriteString(lineBreak); err != nil {
+				return err
+			}
+		}
+	}
+
+	if _, err = buf.WriteTo(f); err != nil {
+		return err
+	}
+	return nil
+}
+
+// Set writes a new value for key.
+// if write to one section, the key need be "section::key".
+// if the section is not existed, it panics.
+func (c *IniConfigContainer) Set(key, value string) error {
+	c.Lock()
+	defer c.Unlock()
+	if len(key) == 0 {
+		return errors.New("key is empty")
+	}
+
+	var (
+		section, k string
+		sectionKey = strings.Split(key, "::")
+	)
+
+	if len(sectionKey) >= 2 {
+		section = sectionKey[0]
+		k = sectionKey[1]
+	} else {
+		section = defaultSection
+		k = sectionKey[0]
+	}
+
+	if _, ok := c.data[section]; !ok {
+		c.data[section] = make(map[string]string)
+	}
+	c.data[section][k] = value
+	return nil
+}
+
+// DIY returns the raw value by a given key.
+func (c *IniConfigContainer) DIY(key string) (v interface{}, err error) {
+	if v, ok := c.data[strings.ToLower(key)]; ok {
+		return v, nil
+	}
+	return v, errors.New("key not find")
+}
+
+// section.key or key
+func (c *IniConfigContainer) getdata(key string) string {
+	if len(key) == 0 {
+		return ""
+	}
+	c.RLock()
+	defer c.RUnlock()
+
+	var (
+		section, k string
+		sectionKey = strings.Split(strings.ToLower(key), "::")
+	)
+	if len(sectionKey) >= 2 {
+		section = sectionKey[0]
+		k = sectionKey[1]
+	} else {
+		section = defaultSection
+		k = sectionKey[0]
+	}
+	if v, ok := c.data[section]; ok {
+		if vv, ok := v[k]; ok {
+			return vv
+		}
+	}
+	return ""
+}
+
+func init() {
+	Register("ini", &IniConfig{})
+}

+ 190 - 0
vendor/github.com/fatedier/beego/config/ini_test.go

@@ -0,0 +1,190 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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 config
+
+import (
+	"fmt"
+	"io/ioutil"
+	"os"
+	"strings"
+	"testing"
+)
+
+func TestIni(t *testing.T) {
+
+	var (
+		inicontext = `
+;comment one
+#comment two
+appname = beeapi
+httpport = 8080
+mysqlport = 3600
+PI = 3.1415976
+runmode = "dev"
+autorender = false
+copyrequestbody = true
+session= on
+cookieon= off
+newreg = OFF
+needlogin = ON
+enableSession = Y
+enableCookie = N
+flag = 1
+path1 = ${GOPATH}
+path2 = ${GOPATH||/home/go}
+[demo]
+key1="asta"
+key2 = "xie"
+CaseInsensitive = true
+peers = one;two;three
+password = ${GOPATH}
+`
+
+		keyValue = map[string]interface{}{
+			"appname":               "beeapi",
+			"httpport":              8080,
+			"mysqlport":             int64(3600),
+			"pi":                    3.1415976,
+			"runmode":               "dev",
+			"autorender":            false,
+			"copyrequestbody":       true,
+			"session":               true,
+			"cookieon":              false,
+			"newreg":                false,
+			"needlogin":             true,
+			"enableSession":         true,
+			"enableCookie":          false,
+			"flag":                  true,
+			"path1":                 os.Getenv("GOPATH"),
+			"path2":                 os.Getenv("GOPATH"),
+			"demo::key1":            "asta",
+			"demo::key2":            "xie",
+			"demo::CaseInsensitive": true,
+			"demo::peers":           []string{"one", "two", "three"},
+			"demo::password":        os.Getenv("GOPATH"),
+			"null":                  "",
+			"demo2::key1":           "",
+			"error":                 "",
+			"emptystrings":          []string{},
+		}
+	)
+
+	f, err := os.Create("testini.conf")
+	if err != nil {
+		t.Fatal(err)
+	}
+	_, err = f.WriteString(inicontext)
+	if err != nil {
+		f.Close()
+		t.Fatal(err)
+	}
+	f.Close()
+	defer os.Remove("testini.conf")
+	iniconf, err := NewConfig("ini", "testini.conf")
+	if err != nil {
+		t.Fatal(err)
+	}
+	for k, v := range keyValue {
+		var err error
+		var value interface{}
+		switch v.(type) {
+		case int:
+			value, err = iniconf.Int(k)
+		case int64:
+			value, err = iniconf.Int64(k)
+		case float64:
+			value, err = iniconf.Float(k)
+		case bool:
+			value, err = iniconf.Bool(k)
+		case []string:
+			value = iniconf.Strings(k)
+		case string:
+			value = iniconf.String(k)
+		default:
+			value, err = iniconf.DIY(k)
+		}
+		if err != nil {
+			t.Fatalf("get key %q value fail,err %s", k, err)
+		} else if fmt.Sprintf("%v", v) != fmt.Sprintf("%v", value) {
+			t.Fatalf("get key %q value, want %v got %v .", k, v, value)
+		}
+
+	}
+	if err = iniconf.Set("name", "astaxie"); err != nil {
+		t.Fatal(err)
+	}
+	if iniconf.String("name") != "astaxie" {
+		t.Fatal("get name error")
+	}
+
+}
+
+func TestIniSave(t *testing.T) {
+
+	const (
+		inicontext = `
+app = app
+;comment one
+#comment two
+# comment three
+appname = beeapi
+httpport = 8080
+# DB Info
+# enable db
+[dbinfo]
+# db type name
+# suport mysql,sqlserver
+name = mysql
+`
+
+		saveResult = `
+app=app
+#comment one
+#comment two
+# comment three
+appname=beeapi
+httpport=8080
+
+# DB Info
+# enable db
+[dbinfo]
+# db type name
+# suport mysql,sqlserver
+name=mysql
+`
+	)
+	cfg, err := NewConfigData("ini", []byte(inicontext))
+	if err != nil {
+		t.Fatal(err)
+	}
+	name := "newIniConfig.ini"
+	if err := cfg.SaveConfigFile(name); err != nil {
+		t.Fatal(err)
+	}
+	defer os.Remove(name)
+
+	if data, err := ioutil.ReadFile(name); err != nil {
+		t.Fatal(err)
+	} else {
+		cfgData := string(data)
+		datas := strings.Split(saveResult, "\n")
+		for _, line := range datas {
+			if strings.Contains(cfgData, line+"\n") == false {
+				t.Fatalf("different after save ini config file. need contains %q", line)
+			}
+		}
+
+	}
+}

+ 266 - 0
vendor/github.com/fatedier/beego/config/json.go

@@ -0,0 +1,266 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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 config
+
+import (
+	"encoding/json"
+	"errors"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"strings"
+	"sync"
+)
+
+// JSONConfig is a json config parser and implements Config interface.
+type JSONConfig struct {
+}
+
+// Parse returns a ConfigContainer with parsed json config map.
+func (js *JSONConfig) Parse(filename string) (Configer, error) {
+	file, err := os.Open(filename)
+	if err != nil {
+		return nil, err
+	}
+	defer file.Close()
+	content, err := ioutil.ReadAll(file)
+	if err != nil {
+		return nil, err
+	}
+
+	return js.ParseData(content)
+}
+
+// ParseData returns a ConfigContainer with json string
+func (js *JSONConfig) ParseData(data []byte) (Configer, error) {
+	x := &JSONConfigContainer{
+		data: make(map[string]interface{}),
+	}
+	err := json.Unmarshal(data, &x.data)
+	if err != nil {
+		var wrappingArray []interface{}
+		err2 := json.Unmarshal(data, &wrappingArray)
+		if err2 != nil {
+			return nil, err
+		}
+		x.data["rootArray"] = wrappingArray
+	}
+
+	x.data = ExpandValueEnvForMap(x.data)
+
+	return x, nil
+}
+
+// JSONConfigContainer A Config represents the json configuration.
+// Only when get value, support key as section:name type.
+type JSONConfigContainer struct {
+	data map[string]interface{}
+	sync.RWMutex
+}
+
+// Bool returns the boolean value for a given key.
+func (c *JSONConfigContainer) Bool(key string) (bool, error) {
+	val := c.getData(key)
+	if val != nil {
+		return ParseBool(val)
+	}
+	return false, fmt.Errorf("not exist key: %q", key)
+}
+
+// DefaultBool return the bool value if has no error
+// otherwise return the defaultval
+func (c *JSONConfigContainer) DefaultBool(key string, defaultval bool) bool {
+	if v, err := c.Bool(key); err == nil {
+		return v
+	}
+	return defaultval
+}
+
+// Int returns the integer value for a given key.
+func (c *JSONConfigContainer) Int(key string) (int, error) {
+	val := c.getData(key)
+	if val != nil {
+		if v, ok := val.(float64); ok {
+			return int(v), nil
+		}
+		return 0, errors.New("not int value")
+	}
+	return 0, errors.New("not exist key:" + key)
+}
+
+// DefaultInt returns the integer value for a given key.
+// if err != nil return defaltval
+func (c *JSONConfigContainer) DefaultInt(key string, defaultval int) int {
+	if v, err := c.Int(key); err == nil {
+		return v
+	}
+	return defaultval
+}
+
+// Int64 returns the int64 value for a given key.
+func (c *JSONConfigContainer) Int64(key string) (int64, error) {
+	val := c.getData(key)
+	if val != nil {
+		if v, ok := val.(float64); ok {
+			return int64(v), nil
+		}
+		return 0, errors.New("not int64 value")
+	}
+	return 0, errors.New("not exist key:" + key)
+}
+
+// DefaultInt64 returns the int64 value for a given key.
+// if err != nil return defaltval
+func (c *JSONConfigContainer) DefaultInt64(key string, defaultval int64) int64 {
+	if v, err := c.Int64(key); err == nil {
+		return v
+	}
+	return defaultval
+}
+
+// Float returns the float value for a given key.
+func (c *JSONConfigContainer) Float(key string) (float64, error) {
+	val := c.getData(key)
+	if val != nil {
+		if v, ok := val.(float64); ok {
+			return v, nil
+		}
+		return 0.0, errors.New("not float64 value")
+	}
+	return 0.0, errors.New("not exist key:" + key)
+}
+
+// DefaultFloat returns the float64 value for a given key.
+// if err != nil return defaltval
+func (c *JSONConfigContainer) DefaultFloat(key string, defaultval float64) float64 {
+	if v, err := c.Float(key); err == nil {
+		return v
+	}
+	return defaultval
+}
+
+// String returns the string value for a given key.
+func (c *JSONConfigContainer) String(key string) string {
+	val := c.getData(key)
+	if val != nil {
+		if v, ok := val.(string); ok {
+			return v
+		}
+	}
+	return ""
+}
+
+// DefaultString returns the string value for a given key.
+// if err != nil return defaltval
+func (c *JSONConfigContainer) DefaultString(key string, defaultval string) string {
+	// TODO FIXME should not use "" to replace non existence
+	if v := c.String(key); v != "" {
+		return v
+	}
+	return defaultval
+}
+
+// Strings returns the []string value for a given key.
+func (c *JSONConfigContainer) Strings(key string) []string {
+	stringVal := c.String(key)
+	if stringVal == "" {
+		return nil
+	}
+	return strings.Split(c.String(key), ";")
+}
+
+// DefaultStrings returns the []string value for a given key.
+// if err != nil return defaltval
+func (c *JSONConfigContainer) DefaultStrings(key string, defaultval []string) []string {
+	if v := c.Strings(key); v != nil {
+		return v
+	}
+	return defaultval
+}
+
+// GetSection returns map for the given section
+func (c *JSONConfigContainer) GetSection(section string) (map[string]string, error) {
+	if v, ok := c.data[section]; ok {
+		return v.(map[string]string), nil
+	}
+	return nil, errors.New("nonexist section " + section)
+}
+
+// SaveConfigFile save the config into file
+func (c *JSONConfigContainer) SaveConfigFile(filename string) (err error) {
+	// Write configuration file by filename.
+	f, err := os.Create(filename)
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+	b, err := json.MarshalIndent(c.data, "", "  ")
+	if err != nil {
+		return err
+	}
+	_, err = f.Write(b)
+	return err
+}
+
+// Set writes a new value for key.
+func (c *JSONConfigContainer) Set(key, val string) error {
+	c.Lock()
+	defer c.Unlock()
+	c.data[key] = val
+	return nil
+}
+
+// DIY returns the raw value by a given key.
+func (c *JSONConfigContainer) DIY(key string) (v interface{}, err error) {
+	val := c.getData(key)
+	if val != nil {
+		return val, nil
+	}
+	return nil, errors.New("not exist key")
+}
+
+// section.key or key
+func (c *JSONConfigContainer) getData(key string) interface{} {
+	if len(key) == 0 {
+		return nil
+	}
+
+	c.RLock()
+	defer c.RUnlock()
+
+	sectionKeys := strings.Split(key, "::")
+	if len(sectionKeys) >= 2 {
+		curValue, ok := c.data[sectionKeys[0]]
+		if !ok {
+			return nil
+		}
+		for _, key := range sectionKeys[1:] {
+			if v, ok := curValue.(map[string]interface{}); ok {
+				if curValue, ok = v[key]; !ok {
+					return nil
+				}
+			}
+		}
+		return curValue
+	}
+	if v, ok := c.data[key]; ok {
+		return v
+	}
+	return nil
+}
+
+func init() {
+	Register("json", &JSONConfig{})
+}

+ 222 - 0
vendor/github.com/fatedier/beego/config/json_test.go

@@ -0,0 +1,222 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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 config
+
+import (
+	"fmt"
+	"os"
+	"testing"
+)
+
+func TestJsonStartsWithArray(t *testing.T) {
+
+	const jsoncontextwitharray = `[
+	{
+		"url": "user",
+		"serviceAPI": "http://www.test.com/user"
+	},
+	{
+		"url": "employee",
+		"serviceAPI": "http://www.test.com/employee"
+	}
+]`
+	f, err := os.Create("testjsonWithArray.conf")
+	if err != nil {
+		t.Fatal(err)
+	}
+	_, err = f.WriteString(jsoncontextwitharray)
+	if err != nil {
+		f.Close()
+		t.Fatal(err)
+	}
+	f.Close()
+	defer os.Remove("testjsonWithArray.conf")
+	jsonconf, err := NewConfig("json", "testjsonWithArray.conf")
+	if err != nil {
+		t.Fatal(err)
+	}
+	rootArray, err := jsonconf.DIY("rootArray")
+	if err != nil {
+		t.Error("array does not exist as element")
+	}
+	rootArrayCasted := rootArray.([]interface{})
+	if rootArrayCasted == nil {
+		t.Error("array from root is nil")
+	} else {
+		elem := rootArrayCasted[0].(map[string]interface{})
+		if elem["url"] != "user" || elem["serviceAPI"] != "http://www.test.com/user" {
+			t.Error("array[0] values are not valid")
+		}
+
+		elem2 := rootArrayCasted[1].(map[string]interface{})
+		if elem2["url"] != "employee" || elem2["serviceAPI"] != "http://www.test.com/employee" {
+			t.Error("array[1] values are not valid")
+		}
+	}
+}
+
+func TestJson(t *testing.T) {
+
+	var (
+		jsoncontext = `{
+"appname": "beeapi",
+"testnames": "foo;bar",
+"httpport": 8080,
+"mysqlport": 3600,
+"PI": 3.1415976, 
+"runmode": "dev",
+"autorender": false,
+"copyrequestbody": true,
+"session": "on",
+"cookieon": "off",
+"newreg": "OFF",
+"needlogin": "ON",
+"enableSession": "Y",
+"enableCookie": "N",
+"flag": 1,
+"path1": "${GOPATH}",
+"path2": "${GOPATH||/home/go}",
+"database": {
+        "host": "host",
+        "port": "port",
+        "database": "database",
+        "username": "username",
+        "password": "${GOPATH}",
+		"conns":{
+			"maxconnection":12,
+			"autoconnect":true,
+			"connectioninfo":"info",
+			"root": "${GOPATH}"
+		}
+    }
+}`
+		keyValue = map[string]interface{}{
+			"appname":                         "beeapi",
+			"testnames":                       []string{"foo", "bar"},
+			"httpport":                        8080,
+			"mysqlport":                       int64(3600),
+			"PI":                              3.1415976,
+			"runmode":                         "dev",
+			"autorender":                      false,
+			"copyrequestbody":                 true,
+			"session":                         true,
+			"cookieon":                        false,
+			"newreg":                          false,
+			"needlogin":                       true,
+			"enableSession":                   true,
+			"enableCookie":                    false,
+			"flag":                            true,
+			"path1":                           os.Getenv("GOPATH"),
+			"path2":                           os.Getenv("GOPATH"),
+			"database::host":                  "host",
+			"database::port":                  "port",
+			"database::database":              "database",
+			"database::password":              os.Getenv("GOPATH"),
+			"database::conns::maxconnection":  12,
+			"database::conns::autoconnect":    true,
+			"database::conns::connectioninfo": "info",
+			"database::conns::root":           os.Getenv("GOPATH"),
+			"unknown":                         "",
+		}
+	)
+
+	f, err := os.Create("testjson.conf")
+	if err != nil {
+		t.Fatal(err)
+	}
+	_, err = f.WriteString(jsoncontext)
+	if err != nil {
+		f.Close()
+		t.Fatal(err)
+	}
+	f.Close()
+	defer os.Remove("testjson.conf")
+	jsonconf, err := NewConfig("json", "testjson.conf")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	for k, v := range keyValue {
+		var err error
+		var value interface{}
+		switch v.(type) {
+		case int:
+			value, err = jsonconf.Int(k)
+		case int64:
+			value, err = jsonconf.Int64(k)
+		case float64:
+			value, err = jsonconf.Float(k)
+		case bool:
+			value, err = jsonconf.Bool(k)
+		case []string:
+			value = jsonconf.Strings(k)
+		case string:
+			value = jsonconf.String(k)
+		default:
+			value, err = jsonconf.DIY(k)
+		}
+		if err != nil {
+			t.Fatalf("get key %q value fatal,%v err %s", k, v, err)
+		} else if fmt.Sprintf("%v", v) != fmt.Sprintf("%v", value) {
+			t.Fatalf("get key %q value, want %v got %v .", k, v, value)
+		}
+
+	}
+	if err = jsonconf.Set("name", "astaxie"); err != nil {
+		t.Fatal(err)
+	}
+	if jsonconf.String("name") != "astaxie" {
+		t.Fatal("get name error")
+	}
+
+	if db, err := jsonconf.DIY("database"); err != nil {
+		t.Fatal(err)
+	} else if m, ok := db.(map[string]interface{}); !ok {
+		t.Log(db)
+		t.Fatal("db not map[string]interface{}")
+	} else {
+		if m["host"].(string) != "host" {
+			t.Fatal("get host err")
+		}
+	}
+
+	if _, err := jsonconf.Int("unknown"); err == nil {
+		t.Error("unknown keys should return an error when expecting an Int")
+	}
+
+	if _, err := jsonconf.Int64("unknown"); err == nil {
+		t.Error("unknown keys should return an error when expecting an Int64")
+	}
+
+	if _, err := jsonconf.Float("unknown"); err == nil {
+		t.Error("unknown keys should return an error when expecting a Float")
+	}
+
+	if _, err := jsonconf.DIY("unknown"); err == nil {
+		t.Error("unknown keys should return an error when expecting an interface{}")
+	}
+
+	if val := jsonconf.String("unknown"); val != "" {
+		t.Error("unknown keys should return an empty string when expecting a String")
+	}
+
+	if _, err := jsonconf.Bool("unknown"); err == nil {
+		t.Error("unknown keys should return an error when expecting a Bool")
+	}
+
+	if !jsonconf.DefaultBool("unknow", true) {
+		t.Error("unknown keys with default value wrong")
+	}
+}

+ 228 - 0
vendor/github.com/fatedier/beego/config/xml/xml.go

@@ -0,0 +1,228 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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 xml for config provider.
+//
+// depend on github.com/beego/x2j.
+//
+// go install github.com/beego/x2j.
+//
+// Usage:
+//  import(
+//    _ "github.com/astaxie/beego/config/xml"
+//      "github.com/astaxie/beego/config"
+//  )
+//
+//  cnf, err := config.NewConfig("xml", "config.xml")
+//
+//More docs http://beego.me/docs/module/config.md
+package xml
+
+import (
+	"encoding/xml"
+	"errors"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"strconv"
+	"strings"
+	"sync"
+
+	"github.com/astaxie/beego/config"
+	"github.com/beego/x2j"
+)
+
+// Config is a xml config parser and implements Config interface.
+// xml configurations should be included in <config></config> tag.
+// only support key/value pair as <key>value</key> as each item.
+type Config struct{}
+
+// Parse returns a ConfigContainer with parsed xml config map.
+func (xc *Config) Parse(filename string) (config.Configer, error) {
+	context, err := ioutil.ReadFile(filename)
+	if err != nil {
+		return nil, err
+	}
+
+	return xc.ParseData(context)
+}
+
+// ParseData xml data
+func (xc *Config) ParseData(data []byte) (config.Configer, error) {
+	x := &ConfigContainer{data: make(map[string]interface{})}
+
+	d, err := x2j.DocToMap(string(data))
+	if err != nil {
+		return nil, err
+	}
+
+	x.data = config.ExpandValueEnvForMap(d["config"].(map[string]interface{}))
+
+	return x, nil
+}
+
+// ConfigContainer A Config represents the xml configuration.
+type ConfigContainer struct {
+	data map[string]interface{}
+	sync.Mutex
+}
+
+// Bool returns the boolean value for a given key.
+func (c *ConfigContainer) Bool(key string) (bool, error) {
+	if v := c.data[key]; v != nil {
+		return config.ParseBool(v)
+	}
+	return false, fmt.Errorf("not exist key: %q", key)
+}
+
+// DefaultBool return the bool value if has no error
+// otherwise return the defaultval
+func (c *ConfigContainer) DefaultBool(key string, defaultval bool) bool {
+	v, err := c.Bool(key)
+	if err != nil {
+		return defaultval
+	}
+	return v
+}
+
+// Int returns the integer value for a given key.
+func (c *ConfigContainer) Int(key string) (int, error) {
+	return strconv.Atoi(c.data[key].(string))
+}
+
+// DefaultInt returns the integer value for a given key.
+// if err != nil return defaltval
+func (c *ConfigContainer) DefaultInt(key string, defaultval int) int {
+	v, err := c.Int(key)
+	if err != nil {
+		return defaultval
+	}
+	return v
+}
+
+// Int64 returns the int64 value for a given key.
+func (c *ConfigContainer) Int64(key string) (int64, error) {
+	return strconv.ParseInt(c.data[key].(string), 10, 64)
+}
+
+// DefaultInt64 returns the int64 value for a given key.
+// if err != nil return defaltval
+func (c *ConfigContainer) DefaultInt64(key string, defaultval int64) int64 {
+	v, err := c.Int64(key)
+	if err != nil {
+		return defaultval
+	}
+	return v
+
+}
+
+// Float returns the float value for a given key.
+func (c *ConfigContainer) Float(key string) (float64, error) {
+	return strconv.ParseFloat(c.data[key].(string), 64)
+}
+
+// DefaultFloat returns the float64 value for a given key.
+// if err != nil return defaltval
+func (c *ConfigContainer) DefaultFloat(key string, defaultval float64) float64 {
+	v, err := c.Float(key)
+	if err != nil {
+		return defaultval
+	}
+	return v
+}
+
+// String returns the string value for a given key.
+func (c *ConfigContainer) String(key string) string {
+	if v, ok := c.data[key].(string); ok {
+		return v
+	}
+	return ""
+}
+
+// DefaultString returns the string value for a given key.
+// if err != nil return defaltval
+func (c *ConfigContainer) DefaultString(key string, defaultval string) string {
+	v := c.String(key)
+	if v == "" {
+		return defaultval
+	}
+	return v
+}
+
+// Strings returns the []string value for a given key.
+func (c *ConfigContainer) Strings(key string) []string {
+	v := c.String(key)
+	if v == "" {
+		return nil
+	}
+	return strings.Split(v, ";")
+}
+
+// DefaultStrings returns the []string value for a given key.
+// if err != nil return defaltval
+func (c *ConfigContainer) DefaultStrings(key string, defaultval []string) []string {
+	v := c.Strings(key)
+	if v == nil {
+		return defaultval
+	}
+	return v
+}
+
+// GetSection returns map for the given section
+func (c *ConfigContainer) GetSection(section string) (map[string]string, error) {
+	if v, ok := c.data[section].(map[string]interface{}); ok {
+		mapstr := make(map[string]string)
+		for k, val := range v {
+			mapstr[k] = config.ToString(val)
+		}
+		return mapstr, nil
+	}
+	return nil, fmt.Errorf("section '%s' not found", section)
+}
+
+// SaveConfigFile save the config into file
+func (c *ConfigContainer) SaveConfigFile(filename string) (err error) {
+	// Write configuration file by filename.
+	f, err := os.Create(filename)
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+	b, err := xml.MarshalIndent(c.data, "  ", "    ")
+	if err != nil {
+		return err
+	}
+	_, err = f.Write(b)
+	return err
+}
+
+// Set writes a new value for key.
+func (c *ConfigContainer) Set(key, val string) error {
+	c.Lock()
+	defer c.Unlock()
+	c.data[key] = val
+	return nil
+}
+
+// DIY returns the raw value by a given key.
+func (c *ConfigContainer) DIY(key string) (v interface{}, err error) {
+	if v, ok := c.data[key]; ok {
+		return v, nil
+	}
+	return nil, errors.New("not exist key")
+}
+
+func init() {
+	config.Register("xml", &Config{})
+}

+ 125 - 0
vendor/github.com/fatedier/beego/config/xml/xml_test.go

@@ -0,0 +1,125 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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 xml
+
+import (
+	"fmt"
+	"os"
+	"testing"
+
+	"github.com/astaxie/beego/config"
+)
+
+func TestXML(t *testing.T) {
+
+	var (
+		//xml parse should incluce in <config></config> tags
+		xmlcontext = `<?xml version="1.0" encoding="UTF-8"?>
+<config>
+<appname>beeapi</appname>
+<httpport>8080</httpport>
+<mysqlport>3600</mysqlport>
+<PI>3.1415976</PI>
+<runmode>dev</runmode>
+<autorender>false</autorender>
+<copyrequestbody>true</copyrequestbody>
+<path1>${GOPATH}</path1>
+<path2>${GOPATH||/home/go}</path2>
+<mysection>
+<id>1</id>
+<name>MySection</name>
+</mysection>
+</config>
+`
+		keyValue = map[string]interface{}{
+			"appname":         "beeapi",
+			"httpport":        8080,
+			"mysqlport":       int64(3600),
+			"PI":              3.1415976,
+			"runmode":         "dev",
+			"autorender":      false,
+			"copyrequestbody": true,
+			"path1":           os.Getenv("GOPATH"),
+			"path2":           os.Getenv("GOPATH"),
+			"error":           "",
+			"emptystrings":    []string{},
+		}
+	)
+
+	f, err := os.Create("testxml.conf")
+	if err != nil {
+		t.Fatal(err)
+	}
+	_, err = f.WriteString(xmlcontext)
+	if err != nil {
+		f.Close()
+		t.Fatal(err)
+	}
+	f.Close()
+	defer os.Remove("testxml.conf")
+
+	xmlconf, err := config.NewConfig("xml", "testxml.conf")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	var xmlsection map[string]string
+	xmlsection, err = xmlconf.GetSection("mysection")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if len(xmlsection) == 0 {
+		t.Error("section should not be empty")
+	}
+
+	for k, v := range keyValue {
+
+		var (
+			value interface{}
+			err   error
+		)
+
+		switch v.(type) {
+		case int:
+			value, err = xmlconf.Int(k)
+		case int64:
+			value, err = xmlconf.Int64(k)
+		case float64:
+			value, err = xmlconf.Float(k)
+		case bool:
+			value, err = xmlconf.Bool(k)
+		case []string:
+			value = xmlconf.Strings(k)
+		case string:
+			value = xmlconf.String(k)
+		default:
+			value, err = xmlconf.DIY(k)
+		}
+		if err != nil {
+			t.Errorf("get key %q value fatal,%v err %s", k, v, err)
+		} else if fmt.Sprintf("%v", v) != fmt.Sprintf("%v", value) {
+			t.Errorf("get key %q value, want %v got %v .", k, v, value)
+		}
+
+	}
+
+	if err = xmlconf.Set("name", "astaxie"); err != nil {
+		t.Fatal(err)
+	}
+	if xmlconf.String("name") != "astaxie" {
+		t.Fatal("get name error")
+	}
+}

+ 297 - 0
vendor/github.com/fatedier/beego/config/yaml/yaml.go

@@ -0,0 +1,297 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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 yaml for config provider
+//
+// depend on github.com/beego/goyaml2
+//
+// go install github.com/beego/goyaml2
+//
+// Usage:
+//  import(
+//   _ "github.com/astaxie/beego/config/yaml"
+//     "github.com/astaxie/beego/config"
+//  )
+//
+//  cnf, err := config.NewConfig("yaml", "config.yaml")
+//
+//More docs http://beego.me/docs/module/config.md
+package yaml
+
+import (
+	"bytes"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"io/ioutil"
+	"log"
+	"os"
+	"strings"
+	"sync"
+
+	"github.com/astaxie/beego/config"
+	"github.com/beego/goyaml2"
+)
+
+// Config is a yaml config parser and implements Config interface.
+type Config struct{}
+
+// Parse returns a ConfigContainer with parsed yaml config map.
+func (yaml *Config) Parse(filename string) (y config.Configer, err error) {
+	cnf, err := ReadYmlReader(filename)
+	if err != nil {
+		return
+	}
+	y = &ConfigContainer{
+		data: cnf,
+	}
+	return
+}
+
+// ParseData parse yaml data
+func (yaml *Config) ParseData(data []byte) (config.Configer, error) {
+	cnf, err := parseYML(data)
+	if err != nil {
+		return nil, err
+	}
+
+	return &ConfigContainer{
+		data: cnf,
+	}, nil
+}
+
+// ReadYmlReader Read yaml file to map.
+// if json like, use json package, unless goyaml2 package.
+func ReadYmlReader(path string) (cnf map[string]interface{}, err error) {
+	buf, err := ioutil.ReadFile(path)
+	if err != nil {
+		return
+	}
+
+	return parseYML(buf)
+}
+
+// parseYML parse yaml formatted []byte to map.
+func parseYML(buf []byte) (cnf map[string]interface{}, err error) {
+	if len(buf) < 3 {
+		return
+	}
+
+	if string(buf[0:1]) == "{" {
+		log.Println("Look like a Json, try json umarshal")
+		err = json.Unmarshal(buf, &cnf)
+		if err == nil {
+			log.Println("It is Json Map")
+			return
+		}
+	}
+
+	data, err := goyaml2.Read(bytes.NewBuffer(buf))
+	if err != nil {
+		log.Println("Goyaml2 ERR>", string(buf), err)
+		return
+	}
+
+	if data == nil {
+		log.Println("Goyaml2 output nil? Pls report bug\n" + string(buf))
+		return
+	}
+	cnf, ok := data.(map[string]interface{})
+	if !ok {
+		log.Println("Not a Map? >> ", string(buf), data)
+		cnf = nil
+	}
+	cnf = config.ExpandValueEnvForMap(cnf)
+	return
+}
+
+// ConfigContainer A Config represents the yaml configuration.
+type ConfigContainer struct {
+	data map[string]interface{}
+	sync.Mutex
+}
+
+// Bool returns the boolean value for a given key.
+func (c *ConfigContainer) Bool(key string) (bool, error) {
+	v, err := c.getData(key)
+	if err != nil {
+		return false, err
+	}
+	return config.ParseBool(v)
+}
+
+// DefaultBool return the bool value if has no error
+// otherwise return the defaultval
+func (c *ConfigContainer) DefaultBool(key string, defaultval bool) bool {
+	v, err := c.Bool(key)
+	if err != nil {
+		return defaultval
+	}
+	return v
+}
+
+// Int returns the integer value for a given key.
+func (c *ConfigContainer) Int(key string) (int, error) {
+	if v, err := c.getData(key); err != nil {
+		return 0, err
+	} else if vv, ok := v.(int); ok {
+		return vv, nil
+	} else if vv, ok := v.(int64); ok {
+		return int(vv), nil
+	}
+	return 0, errors.New("not int value")
+}
+
+// DefaultInt returns the integer value for a given key.
+// if err != nil return defaltval
+func (c *ConfigContainer) DefaultInt(key string, defaultval int) int {
+	v, err := c.Int(key)
+	if err != nil {
+		return defaultval
+	}
+	return v
+}
+
+// Int64 returns the int64 value for a given key.
+func (c *ConfigContainer) Int64(key string) (int64, error) {
+	if v, err := c.getData(key); err != nil {
+		return 0, err
+	} else if vv, ok := v.(int64); ok {
+		return vv, nil
+	}
+	return 0, errors.New("not bool value")
+}
+
+// DefaultInt64 returns the int64 value for a given key.
+// if err != nil return defaltval
+func (c *ConfigContainer) DefaultInt64(key string, defaultval int64) int64 {
+	v, err := c.Int64(key)
+	if err != nil {
+		return defaultval
+	}
+	return v
+}
+
+// Float returns the float value for a given key.
+func (c *ConfigContainer) Float(key string) (float64, error) {
+	if v, err := c.getData(key); err != nil {
+		return 0.0, err
+	} else if vv, ok := v.(float64); ok {
+		return vv, nil
+	} else if vv, ok := v.(int); ok {
+		return float64(vv), nil
+	} else if vv, ok := v.(int64); ok {
+		return float64(vv), nil
+	}
+	return 0.0, errors.New("not float64 value")
+}
+
+// DefaultFloat returns the float64 value for a given key.
+// if err != nil return defaltval
+func (c *ConfigContainer) DefaultFloat(key string, defaultval float64) float64 {
+	v, err := c.Float(key)
+	if err != nil {
+		return defaultval
+	}
+	return v
+}
+
+// String returns the string value for a given key.
+func (c *ConfigContainer) String(key string) string {
+	if v, err := c.getData(key); err == nil {
+		if vv, ok := v.(string); ok {
+			return vv
+		}
+	}
+	return ""
+}
+
+// DefaultString returns the string value for a given key.
+// if err != nil return defaltval
+func (c *ConfigContainer) DefaultString(key string, defaultval string) string {
+	v := c.String(key)
+	if v == "" {
+		return defaultval
+	}
+	return v
+}
+
+// Strings returns the []string value for a given key.
+func (c *ConfigContainer) Strings(key string) []string {
+	v := c.String(key)
+	if v == "" {
+		return nil
+	}
+	return strings.Split(v, ";")
+}
+
+// DefaultStrings returns the []string value for a given key.
+// if err != nil return defaltval
+func (c *ConfigContainer) DefaultStrings(key string, defaultval []string) []string {
+	v := c.Strings(key)
+	if v == nil {
+		return defaultval
+	}
+	return v
+}
+
+// GetSection returns map for the given section
+func (c *ConfigContainer) GetSection(section string) (map[string]string, error) {
+
+	if v, ok := c.data[section]; ok {
+		return v.(map[string]string), nil
+	}
+	return nil, errors.New("not exist section")
+}
+
+// SaveConfigFile save the config into file
+func (c *ConfigContainer) SaveConfigFile(filename string) (err error) {
+	// Write configuration file by filename.
+	f, err := os.Create(filename)
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+	err = goyaml2.Write(f, c.data)
+	return err
+}
+
+// Set writes a new value for key.
+func (c *ConfigContainer) Set(key, val string) error {
+	c.Lock()
+	defer c.Unlock()
+	c.data[key] = val
+	return nil
+}
+
+// DIY returns the raw value by a given key.
+func (c *ConfigContainer) DIY(key string) (v interface{}, err error) {
+	return c.getData(key)
+}
+
+func (c *ConfigContainer) getData(key string) (interface{}, error) {
+
+	if len(key) == 0 {
+		return nil, errors.New("key is empty")
+	}
+
+	if v, ok := c.data[key]; ok {
+		return v, nil
+	}
+	return nil, fmt.Errorf("not exist key %q", key)
+}
+
+func init() {
+	config.Register("yaml", &Config{})
+}

+ 115 - 0
vendor/github.com/fatedier/beego/config/yaml/yaml_test.go

@@ -0,0 +1,115 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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 yaml
+
+import (
+	"fmt"
+	"os"
+	"testing"
+
+	"github.com/astaxie/beego/config"
+)
+
+func TestYaml(t *testing.T) {
+
+	var (
+		yamlcontext = `
+"appname": beeapi
+"httpport": 8080
+"mysqlport": 3600
+"PI": 3.1415976
+"runmode": dev
+"autorender": false
+"copyrequestbody": true
+"PATH": GOPATH
+"path1": ${GOPATH}
+"path2": ${GOPATH||/home/go}
+"empty": "" 
+`
+
+		keyValue = map[string]interface{}{
+			"appname":         "beeapi",
+			"httpport":        8080,
+			"mysqlport":       int64(3600),
+			"PI":              3.1415976,
+			"runmode":         "dev",
+			"autorender":      false,
+			"copyrequestbody": true,
+			"PATH":            "GOPATH",
+			"path1":           os.Getenv("GOPATH"),
+			"path2":           os.Getenv("GOPATH"),
+			"error":           "",
+			"emptystrings":    []string{},
+		}
+	)
+	f, err := os.Create("testyaml.conf")
+	if err != nil {
+		t.Fatal(err)
+	}
+	_, err = f.WriteString(yamlcontext)
+	if err != nil {
+		f.Close()
+		t.Fatal(err)
+	}
+	f.Close()
+	defer os.Remove("testyaml.conf")
+	yamlconf, err := config.NewConfig("yaml", "testyaml.conf")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if yamlconf.String("appname") != "beeapi" {
+		t.Fatal("appname not equal to beeapi")
+	}
+
+	for k, v := range keyValue {
+
+		var (
+			value interface{}
+			err   error
+		)
+
+		switch v.(type) {
+		case int:
+			value, err = yamlconf.Int(k)
+		case int64:
+			value, err = yamlconf.Int64(k)
+		case float64:
+			value, err = yamlconf.Float(k)
+		case bool:
+			value, err = yamlconf.Bool(k)
+		case []string:
+			value = yamlconf.Strings(k)
+		case string:
+			value = yamlconf.String(k)
+		default:
+			value, err = yamlconf.DIY(k)
+		}
+		if err != nil {
+			t.Errorf("get key %q value fatal,%v err %s", k, v, err)
+		} else if fmt.Sprintf("%v", v) != fmt.Sprintf("%v", value) {
+			t.Errorf("get key %q value, want %v got %v .", k, v, value)
+		}
+
+	}
+
+	if err = yamlconf.Set("name", "astaxie"); err != nil {
+		t.Fatal(err)
+	}
+	if yamlconf.String("name") != "astaxie" {
+		t.Fatal("get name error")
+	}
+
+}

+ 138 - 0
vendor/github.com/fatedier/beego/config_test.go

@@ -0,0 +1,138 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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 beego
+
+import (
+	"encoding/json"
+	"reflect"
+	"testing"
+
+	"github.com/astaxie/beego/config"
+)
+
+func TestDefaults(t *testing.T) {
+	if BConfig.WebConfig.FlashName != "BEEGO_FLASH" {
+		t.Errorf("FlashName was not set to default.")
+	}
+
+	if BConfig.WebConfig.FlashSeparator != "BEEGOFLASH" {
+		t.Errorf("FlashName was not set to default.")
+	}
+}
+
+func TestAssignConfig_01(t *testing.T) {
+	_BConfig := &Config{}
+	_BConfig.AppName = "beego_test"
+	jcf := &config.JSONConfig{}
+	ac, _ := jcf.ParseData([]byte(`{"AppName":"beego_json"}`))
+	assignSingleConfig(_BConfig, ac)
+	if _BConfig.AppName != "beego_json" {
+		t.Log(_BConfig)
+		t.FailNow()
+	}
+}
+
+func TestAssignConfig_02(t *testing.T) {
+	_BConfig := &Config{}
+	bs, _ := json.Marshal(newBConfig())
+
+	jsonMap := map[string]interface{}{}
+	json.Unmarshal(bs, &jsonMap)
+
+	configMap := map[string]interface{}{}
+	for k, v := range jsonMap {
+		if reflect.TypeOf(v).Kind() == reflect.Map {
+			for k1, v1 := range v.(map[string]interface{}) {
+				if reflect.TypeOf(v1).Kind() == reflect.Map {
+					for k2, v2 := range v1.(map[string]interface{}) {
+						configMap[k2] = v2
+					}
+				} else {
+					configMap[k1] = v1
+				}
+			}
+		} else {
+			configMap[k] = v
+		}
+	}
+	configMap["MaxMemory"] = 1024
+	configMap["Graceful"] = true
+	configMap["XSRFExpire"] = 32
+	configMap["SessionProviderConfig"] = "file"
+	configMap["FileLineNum"] = true
+
+	jcf := &config.JSONConfig{}
+	bs, _ = json.Marshal(configMap)
+	ac, _ := jcf.ParseData([]byte(bs))
+
+	for _, i := range []interface{}{_BConfig, &_BConfig.Listen, &_BConfig.WebConfig, &_BConfig.Log, &_BConfig.WebConfig.Session} {
+		assignSingleConfig(i, ac)
+	}
+
+	if _BConfig.MaxMemory != 1024 {
+		t.Log(_BConfig.MaxMemory)
+		t.FailNow()
+	}
+
+	if !_BConfig.Listen.Graceful {
+		t.Log(_BConfig.Listen.Graceful)
+		t.FailNow()
+	}
+
+	if _BConfig.WebConfig.XSRFExpire != 32 {
+		t.Log(_BConfig.WebConfig.XSRFExpire)
+		t.FailNow()
+	}
+
+	if _BConfig.WebConfig.Session.SessionProviderConfig != "file" {
+		t.Log(_BConfig.WebConfig.Session.SessionProviderConfig)
+		t.FailNow()
+	}
+
+	if !_BConfig.Log.FileLineNum {
+		t.Log(_BConfig.Log.FileLineNum)
+		t.FailNow()
+	}
+
+}
+
+func TestAssignConfig_03(t *testing.T) {
+	jcf := &config.JSONConfig{}
+	ac, _ := jcf.ParseData([]byte(`{"AppName":"beego"}`))
+	ac.Set("AppName", "test_app")
+	ac.Set("RunMode", "online")
+	ac.Set("StaticDir", "download:down download2:down2")
+	ac.Set("StaticExtensionsToGzip", ".css,.js,.html,.jpg,.png")
+	assignConfig(ac)
+
+	t.Logf("%#v", BConfig)
+
+	if BConfig.AppName != "test_app" {
+		t.FailNow()
+	}
+
+	if BConfig.RunMode != "online" {
+		t.FailNow()
+	}
+	if BConfig.WebConfig.StaticDir["/download"] != "down" {
+		t.FailNow()
+	}
+	if BConfig.WebConfig.StaticDir["/download2"] != "down2" {
+		t.FailNow()
+	}
+	if len(BConfig.WebConfig.StaticExtensionsToGzip) != 5 {
+		t.FailNow()
+	}
+}

+ 231 - 0
vendor/github.com/fatedier/beego/context/acceptencoder.go

@@ -0,0 +1,231 @@
+// Copyright 2015 beego Author. All Rights Reserved.
+//
+// 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 context
+
+import (
+	"bytes"
+	"compress/flate"
+	"compress/gzip"
+	"compress/zlib"
+	"io"
+	"net/http"
+	"os"
+	"strconv"
+	"strings"
+	"sync"
+)
+
+var (
+	//Default size==20B same as nginx
+	defaultGzipMinLength = 20
+	//Content will only be compressed if content length is either unknown or greater than gzipMinLength.
+	gzipMinLength = defaultGzipMinLength
+	//The compression level used for deflate compression. (0-9).
+	gzipCompressLevel int
+	//List of HTTP methods to compress. If not set, only GET requests are compressed.
+	includedMethods map[string]bool
+	getMethodOnly   bool
+)
+
+func InitGzip(minLength, compressLevel int, methods []string) {
+	if minLength >= 0 {
+		gzipMinLength = minLength
+	}
+	gzipCompressLevel = compressLevel
+	if gzipCompressLevel < flate.NoCompression || gzipCompressLevel > flate.BestCompression {
+		gzipCompressLevel = flate.BestSpeed
+	}
+	getMethodOnly = (len(methods) == 0) || (len(methods) == 1 && strings.ToUpper(methods[0]) == "GET")
+	includedMethods = make(map[string]bool, len(methods))
+	for _, v := range methods {
+		includedMethods[strings.ToUpper(v)] = true
+	}
+}
+
+type resetWriter interface {
+	io.Writer
+	Reset(w io.Writer)
+}
+
+type nopResetWriter struct {
+	io.Writer
+}
+
+func (n nopResetWriter) Reset(w io.Writer) {
+	//do nothing
+}
+
+type acceptEncoder struct {
+	name                    string
+	levelEncode             func(int) resetWriter
+	customCompressLevelPool *sync.Pool
+	bestCompressionPool     *sync.Pool
+}
+
+func (ac acceptEncoder) encode(wr io.Writer, level int) resetWriter {
+	if ac.customCompressLevelPool == nil || ac.bestCompressionPool == nil {
+		return nopResetWriter{wr}
+	}
+	var rwr resetWriter
+	switch level {
+	case flate.BestSpeed:
+		rwr = ac.customCompressLevelPool.Get().(resetWriter)
+	case flate.BestCompression:
+		rwr = ac.bestCompressionPool.Get().(resetWriter)
+	default:
+		rwr = ac.levelEncode(level)
+	}
+	rwr.Reset(wr)
+	return rwr
+}
+
+func (ac acceptEncoder) put(wr resetWriter, level int) {
+	if ac.customCompressLevelPool == nil || ac.bestCompressionPool == nil {
+		return
+	}
+	wr.Reset(nil)
+
+	//notice
+	//compressionLevel==BestCompression DOES NOT MATTER
+	//sync.Pool will not memory leak
+
+	switch level {
+	case gzipCompressLevel:
+		ac.customCompressLevelPool.Put(wr)
+	case flate.BestCompression:
+		ac.bestCompressionPool.Put(wr)
+	}
+}
+
+var (
+	noneCompressEncoder = acceptEncoder{"", nil, nil, nil}
+	gzipCompressEncoder = acceptEncoder{
+		name:                    "gzip",
+		levelEncode:             func(level int) resetWriter { wr, _ := gzip.NewWriterLevel(nil, level); return wr },
+		customCompressLevelPool: &sync.Pool{New: func() interface{} { wr, _ := gzip.NewWriterLevel(nil, gzipCompressLevel); return wr }},
+		bestCompressionPool:     &sync.Pool{New: func() interface{} { wr, _ := gzip.NewWriterLevel(nil, flate.BestCompression); return wr }},
+	}
+
+	//according to the sec :http://tools.ietf.org/html/rfc2616#section-3.5 ,the deflate compress in http is zlib indeed
+	//deflate
+	//The "zlib" format defined in RFC 1950 [31] in combination with
+	//the "deflate" compression mechanism described in RFC 1951 [29].
+	deflateCompressEncoder = acceptEncoder{
+		name:                    "deflate",
+		levelEncode:             func(level int) resetWriter { wr, _ := zlib.NewWriterLevel(nil, level); return wr },
+		customCompressLevelPool: &sync.Pool{New: func() interface{} { wr, _ := zlib.NewWriterLevel(nil, gzipCompressLevel); return wr }},
+		bestCompressionPool:     &sync.Pool{New: func() interface{} { wr, _ := zlib.NewWriterLevel(nil, flate.BestCompression); return wr }},
+	}
+)
+
+var (
+	encoderMap = map[string]acceptEncoder{ // all the other compress methods will ignore
+		"gzip":     gzipCompressEncoder,
+		"deflate":  deflateCompressEncoder,
+		"*":        gzipCompressEncoder, // * means any compress will accept,we prefer gzip
+		"identity": noneCompressEncoder, // identity means none-compress
+	}
+)
+
+// WriteFile reads from file and writes to writer by the specific encoding(gzip/deflate)
+func WriteFile(encoding string, writer io.Writer, file *os.File) (bool, string, error) {
+	return writeLevel(encoding, writer, file, flate.BestCompression)
+}
+
+// WriteBody reads  writes content to writer by the specific encoding(gzip/deflate)
+func WriteBody(encoding string, writer io.Writer, content []byte) (bool, string, error) {
+	if encoding == "" || len(content) < gzipMinLength {
+		_, err := writer.Write(content)
+		return false, "", err
+	}
+	return writeLevel(encoding, writer, bytes.NewReader(content), gzipCompressLevel)
+}
+
+// writeLevel reads from reader,writes to writer by specific encoding and compress level
+// the compress level is defined by deflate package
+func writeLevel(encoding string, writer io.Writer, reader io.Reader, level int) (bool, string, error) {
+	var outputWriter resetWriter
+	var err error
+	var ce = noneCompressEncoder
+
+	if cf, ok := encoderMap[encoding]; ok {
+		ce = cf
+	}
+	encoding = ce.name
+	outputWriter = ce.encode(writer, level)
+	defer ce.put(outputWriter, level)
+
+	_, err = io.Copy(outputWriter, reader)
+	if err != nil {
+		return false, "", err
+	}
+
+	switch outputWriter.(type) {
+	case io.WriteCloser:
+		outputWriter.(io.WriteCloser).Close()
+	}
+	return encoding != "", encoding, nil
+}
+
+// ParseEncoding will extract the right encoding for response
+// the Accept-Encoding's sec is here:
+// http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3
+func ParseEncoding(r *http.Request) string {
+	if r == nil {
+		return ""
+	}
+	if (getMethodOnly && r.Method == "GET") || includedMethods[r.Method] {
+		return parseEncoding(r)
+	}
+	return ""
+}
+
+type q struct {
+	name  string
+	value float64
+}
+
+func parseEncoding(r *http.Request) string {
+	acceptEncoding := r.Header.Get("Accept-Encoding")
+	if acceptEncoding == "" {
+		return ""
+	}
+	var lastQ q
+	for _, v := range strings.Split(acceptEncoding, ",") {
+		v = strings.TrimSpace(v)
+		if v == "" {
+			continue
+		}
+		vs := strings.Split(v, ";")
+		var cf acceptEncoder
+		var ok bool
+		if cf, ok = encoderMap[vs[0]]; !ok {
+			continue
+		}
+		if len(vs) == 1 {
+			return cf.name
+		}
+		if len(vs) == 2 {
+			f, _ := strconv.ParseFloat(strings.Replace(vs[1], "q=", "", -1), 64)
+			if f == 0 {
+				continue
+			}
+			if f > lastQ.value {
+				lastQ = q{cf.name, f}
+			}
+		}
+	}
+	return lastQ.name
+}

+ 59 - 0
vendor/github.com/fatedier/beego/context/acceptencoder_test.go

@@ -0,0 +1,59 @@
+// Copyright 2015 beego Author. All Rights Reserved.
+//
+// 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 context
+
+import (
+	"net/http"
+	"testing"
+)
+
+func Test_ExtractEncoding(t *testing.T) {
+	if parseEncoding(&http.Request{Header: map[string][]string{"Accept-Encoding": {"gzip,deflate"}}}) != "gzip" {
+		t.Fail()
+	}
+	if parseEncoding(&http.Request{Header: map[string][]string{"Accept-Encoding": {"deflate,gzip"}}}) != "deflate" {
+		t.Fail()
+	}
+	if parseEncoding(&http.Request{Header: map[string][]string{"Accept-Encoding": {"gzip;q=.5,deflate"}}}) != "deflate" {
+		t.Fail()
+	}
+	if parseEncoding(&http.Request{Header: map[string][]string{"Accept-Encoding": {"gzip;q=.5,deflate;q=0.3"}}}) != "gzip" {
+		t.Fail()
+	}
+	if parseEncoding(&http.Request{Header: map[string][]string{"Accept-Encoding": {"gzip;q=0,deflate"}}}) != "deflate" {
+		t.Fail()
+	}
+	if parseEncoding(&http.Request{Header: map[string][]string{"Accept-Encoding": {"deflate;q=0.5,gzip;q=0.5,identity"}}}) != "" {
+		t.Fail()
+	}
+	if parseEncoding(&http.Request{Header: map[string][]string{"Accept-Encoding": {"*"}}}) != "gzip" {
+		t.Fail()
+	}
+	if parseEncoding(&http.Request{Header: map[string][]string{"Accept-Encoding": {"x,gzip,deflate"}}}) != "gzip" {
+		t.Fail()
+	}
+	if parseEncoding(&http.Request{Header: map[string][]string{"Accept-Encoding": {"gzip,x,deflate"}}}) != "gzip" {
+		t.Fail()
+	}
+	if parseEncoding(&http.Request{Header: map[string][]string{"Accept-Encoding": {"gzip;q=0.5,x,deflate"}}}) != "deflate" {
+		t.Fail()
+	}
+	if parseEncoding(&http.Request{Header: map[string][]string{"Accept-Encoding": {"x"}}}) != "" {
+		t.Fail()
+	}
+	if parseEncoding(&http.Request{Header: map[string][]string{"Accept-Encoding": {"gzip;q=0.5,x;q=0.8"}}}) != "gzip" {
+		t.Fail()
+	}
+}

+ 230 - 0
vendor/github.com/fatedier/beego/context/context.go

@@ -0,0 +1,230 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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 context provide the context utils
+// Usage:
+//
+//	import "github.com/astaxie/beego/context"
+//
+//	ctx := context.Context{Request:req,ResponseWriter:rw}
+//
+//  more docs http://beego.me/docs/module/context.md
+package context
+
+import (
+	"bufio"
+	"crypto/hmac"
+	"crypto/sha1"
+	"encoding/base64"
+	"errors"
+	"fmt"
+	"net"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/astaxie/beego/utils"
+)
+
+// NewContext return the Context with Input and Output
+func NewContext() *Context {
+	return &Context{
+		Input:  NewInput(),
+		Output: NewOutput(),
+	}
+}
+
+// Context Http request context struct including BeegoInput, BeegoOutput, http.Request and http.ResponseWriter.
+// BeegoInput and BeegoOutput provides some api to operate request and response more easily.
+type Context struct {
+	Input          *BeegoInput
+	Output         *BeegoOutput
+	Request        *http.Request
+	ResponseWriter *Response
+	_xsrfToken     string
+}
+
+// Reset init Context, BeegoInput and BeegoOutput
+func (ctx *Context) Reset(rw http.ResponseWriter, r *http.Request) {
+	ctx.Request = r
+	if ctx.ResponseWriter == nil {
+		ctx.ResponseWriter = &Response{}
+	}
+	ctx.ResponseWriter.reset(rw)
+	ctx.Input.Reset(ctx)
+	ctx.Output.Reset(ctx)
+	ctx._xsrfToken = ""
+}
+
+// Redirect does redirection to localurl with http header status code.
+func (ctx *Context) Redirect(status int, localurl string) {
+	http.Redirect(ctx.ResponseWriter, ctx.Request, localurl, status)
+}
+
+// Abort stops this request.
+// if beego.ErrorMaps exists, panic body.
+func (ctx *Context) Abort(status int, body string) {
+	ctx.Output.SetStatus(status)
+	panic(body)
+}
+
+// WriteString Write string to response body.
+// it sends response body.
+func (ctx *Context) WriteString(content string) {
+	ctx.ResponseWriter.Write([]byte(content))
+}
+
+// GetCookie Get cookie from request by a given key.
+// It's alias of BeegoInput.Cookie.
+func (ctx *Context) GetCookie(key string) string {
+	return ctx.Input.Cookie(key)
+}
+
+// SetCookie Set cookie for response.
+// It's alias of BeegoOutput.Cookie.
+func (ctx *Context) SetCookie(name string, value string, others ...interface{}) {
+	ctx.Output.Cookie(name, value, others...)
+}
+
+// GetSecureCookie Get secure cookie from request by a given key.
+func (ctx *Context) GetSecureCookie(Secret, key string) (string, bool) {
+	val := ctx.Input.Cookie(key)
+	if val == "" {
+		return "", false
+	}
+
+	parts := strings.SplitN(val, "|", 3)
+
+	if len(parts) != 3 {
+		return "", false
+	}
+
+	vs := parts[0]
+	timestamp := parts[1]
+	sig := parts[2]
+
+	h := hmac.New(sha1.New, []byte(Secret))
+	fmt.Fprintf(h, "%s%s", vs, timestamp)
+
+	if fmt.Sprintf("%02x", h.Sum(nil)) != sig {
+		return "", false
+	}
+	res, _ := base64.URLEncoding.DecodeString(vs)
+	return string(res), true
+}
+
+// SetSecureCookie Set Secure cookie for response.
+func (ctx *Context) SetSecureCookie(Secret, name, value string, others ...interface{}) {
+	vs := base64.URLEncoding.EncodeToString([]byte(value))
+	timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
+	h := hmac.New(sha1.New, []byte(Secret))
+	fmt.Fprintf(h, "%s%s", vs, timestamp)
+	sig := fmt.Sprintf("%02x", h.Sum(nil))
+	cookie := strings.Join([]string{vs, timestamp, sig}, "|")
+	ctx.Output.Cookie(name, cookie, others...)
+}
+
+// XSRFToken creates a xsrf token string and returns.
+func (ctx *Context) XSRFToken(key string, expire int64) string {
+	if ctx._xsrfToken == "" {
+		token, ok := ctx.GetSecureCookie(key, "_xsrf")
+		if !ok {
+			token = string(utils.RandomCreateBytes(32))
+			ctx.SetSecureCookie(key, "_xsrf", token, expire)
+		}
+		ctx._xsrfToken = token
+	}
+	return ctx._xsrfToken
+}
+
+// CheckXSRFCookie checks xsrf token in this request is valid or not.
+// the token can provided in request header "X-Xsrftoken" and "X-CsrfToken"
+// or in form field value named as "_xsrf".
+func (ctx *Context) CheckXSRFCookie() bool {
+	token := ctx.Input.Query("_xsrf")
+	if token == "" {
+		token = ctx.Request.Header.Get("X-Xsrftoken")
+	}
+	if token == "" {
+		token = ctx.Request.Header.Get("X-Csrftoken")
+	}
+	if token == "" {
+		ctx.Abort(403, "'_xsrf' argument missing from POST")
+		return false
+	}
+	if ctx._xsrfToken != token {
+		ctx.Abort(403, "XSRF cookie does not match POST argument")
+		return false
+	}
+	return true
+}
+
+//Response is a wrapper for the http.ResponseWriter
+//started set to true if response was written to then don't execute other handler
+type Response struct {
+	http.ResponseWriter
+	Started bool
+	Status  int
+}
+
+func (r *Response) reset(rw http.ResponseWriter) {
+	r.ResponseWriter = rw
+	r.Status = 0
+	r.Started = false
+}
+
+// Write writes the data to the connection as part of an HTTP reply,
+// and sets `started` to true.
+// started means the response has sent out.
+func (r *Response) Write(p []byte) (int, error) {
+	r.Started = true
+	return r.ResponseWriter.Write(p)
+}
+
+// WriteHeader sends an HTTP response header with status code,
+// and sets `started` to true.
+func (r *Response) WriteHeader(code int) {
+	if r.Status > 0 {
+		//prevent multiple response.WriteHeader calls
+		return
+	}
+	r.Status = code
+	r.Started = true
+	r.ResponseWriter.WriteHeader(code)
+}
+
+// Hijack hijacker for http
+func (r *Response) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+	hj, ok := r.ResponseWriter.(http.Hijacker)
+	if !ok {
+		return nil, nil, errors.New("webserver doesn't support hijacking")
+	}
+	return hj.Hijack()
+}
+
+// Flush http.Flusher
+func (r *Response) Flush() {
+	if f, ok := r.ResponseWriter.(http.Flusher); ok {
+		f.Flush()
+	}
+}
+
+// CloseNotify http.CloseNotifier
+func (r *Response) CloseNotify() <-chan bool {
+	if cn, ok := r.ResponseWriter.(http.CloseNotifier); ok {
+		return cn.CloseNotify()
+	}
+	return nil
+}

+ 47 - 0
vendor/github.com/fatedier/beego/context/context_test.go

@@ -0,0 +1,47 @@
+// Copyright 2016 beego Author. All Rights Reserved.
+//
+// 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 context
+
+import (
+	"net/http"
+	"net/http/httptest"
+	"testing"
+)
+
+func TestXsrfReset_01(t *testing.T) {
+	r := &http.Request{}
+	c := NewContext()
+	c.Request = r
+	c.ResponseWriter = &Response{}
+	c.ResponseWriter.reset(httptest.NewRecorder())
+	c.Output.Reset(c)
+	c.Input.Reset(c)
+	c.XSRFToken("key", 16)
+	if c._xsrfToken == "" {
+		t.FailNow()
+	}
+	token := c._xsrfToken
+	c.Reset(&Response{ResponseWriter: httptest.NewRecorder()}, r)
+	if c._xsrfToken != "" {
+		t.FailNow()
+	}
+	c.XSRFToken("key", 16)
+	if c._xsrfToken == "" {
+		t.FailNow()
+	}
+	if token == c._xsrfToken {
+		t.FailNow()
+	}
+}

+ 650 - 0
vendor/github.com/fatedier/beego/context/input.go

@@ -0,0 +1,650 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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 context
+
+import (
+	"bytes"
+	"errors"
+	"io"
+	"io/ioutil"
+	"net/url"
+	"reflect"
+	"regexp"
+	"strconv"
+	"strings"
+
+	"github.com/astaxie/beego/session"
+)
+
+// Regexes for checking the accept headers
+// TODO make sure these are correct
+var (
+	acceptsHTMLRegex = regexp.MustCompile(`(text/html|application/xhtml\+xml)(?:,|$)`)
+	acceptsXMLRegex  = regexp.MustCompile(`(application/xml|text/xml)(?:,|$)`)
+	acceptsJSONRegex = regexp.MustCompile(`(application/json)(?:,|$)`)
+	maxParam         = 50
+)
+
+// BeegoInput operates the http request header, data, cookie and body.
+// it also contains router params and current session.
+type BeegoInput struct {
+	Context       *Context
+	CruSession    session.Store
+	pnames        []string
+	pvalues       []string
+	data          map[interface{}]interface{} // store some values in this context when calling context in filter or controller.
+	RequestBody   []byte
+	RunMethod     string
+	RunController reflect.Type
+}
+
+// NewInput return BeegoInput generated by Context.
+func NewInput() *BeegoInput {
+	return &BeegoInput{
+		pnames:  make([]string, 0, maxParam),
+		pvalues: make([]string, 0, maxParam),
+		data:    make(map[interface{}]interface{}),
+	}
+}
+
+// Reset init the BeegoInput
+func (input *BeegoInput) Reset(ctx *Context) {
+	input.Context = ctx
+	input.CruSession = nil
+	input.pnames = input.pnames[:0]
+	input.pvalues = input.pvalues[:0]
+	input.data = nil
+	input.RequestBody = []byte{}
+}
+
+// Protocol returns request protocol name, such as HTTP/1.1 .
+func (input *BeegoInput) Protocol() string {
+	return input.Context.Request.Proto
+}
+
+// URI returns full request url with query string, fragment.
+func (input *BeegoInput) URI() string {
+	return input.Context.Request.RequestURI
+}
+
+// URL returns request url path (without query string, fragment).
+func (input *BeegoInput) URL() string {
+	return input.Context.Request.URL.Path
+}
+
+// Site returns base site url as scheme://domain type.
+func (input *BeegoInput) Site() string {
+	return input.Scheme() + "://" + input.Domain()
+}
+
+// Scheme returns request scheme as "http" or "https".
+func (input *BeegoInput) Scheme() string {
+	if scheme := input.Header("X-Forwarded-Proto"); scheme != "" {
+		return scheme
+	}
+	if input.Context.Request.URL.Scheme != "" {
+		return input.Context.Request.URL.Scheme
+	}
+	if input.Context.Request.TLS == nil {
+		return "http"
+	}
+	return "https"
+}
+
+// Domain returns host name.
+// Alias of Host method.
+func (input *BeegoInput) Domain() string {
+	return input.Host()
+}
+
+// Host returns host name.
+// if no host info in request, return localhost.
+func (input *BeegoInput) Host() string {
+	if input.Context.Request.Host != "" {
+		hostParts := strings.Split(input.Context.Request.Host, ":")
+		if len(hostParts) > 0 {
+			return hostParts[0]
+		}
+		return input.Context.Request.Host
+	}
+	return "localhost"
+}
+
+// Method returns http request method.
+func (input *BeegoInput) Method() string {
+	return input.Context.Request.Method
+}
+
+// Is returns boolean of this request is on given method, such as Is("POST").
+func (input *BeegoInput) Is(method string) bool {
+	return input.Method() == method
+}
+
+// IsGet Is this a GET method request?
+func (input *BeegoInput) IsGet() bool {
+	return input.Is("GET")
+}
+
+// IsPost Is this a POST method request?
+func (input *BeegoInput) IsPost() bool {
+	return input.Is("POST")
+}
+
+// IsHead Is this a Head method request?
+func (input *BeegoInput) IsHead() bool {
+	return input.Is("HEAD")
+}
+
+// IsOptions Is this a OPTIONS method request?
+func (input *BeegoInput) IsOptions() bool {
+	return input.Is("OPTIONS")
+}
+
+// IsPut Is this a PUT method request?
+func (input *BeegoInput) IsPut() bool {
+	return input.Is("PUT")
+}
+
+// IsDelete Is this a DELETE method request?
+func (input *BeegoInput) IsDelete() bool {
+	return input.Is("DELETE")
+}
+
+// IsPatch Is this a PATCH method request?
+func (input *BeegoInput) IsPatch() bool {
+	return input.Is("PATCH")
+}
+
+// IsAjax returns boolean of this request is generated by ajax.
+func (input *BeegoInput) IsAjax() bool {
+	return input.Header("X-Requested-With") == "XMLHttpRequest"
+}
+
+// IsSecure returns boolean of this request is in https.
+func (input *BeegoInput) IsSecure() bool {
+	return input.Scheme() == "https"
+}
+
+// IsWebsocket returns boolean of this request is in webSocket.
+func (input *BeegoInput) IsWebsocket() bool {
+	return input.Header("Upgrade") == "websocket"
+}
+
+// IsUpload returns boolean of whether file uploads in this request or not..
+func (input *BeegoInput) IsUpload() bool {
+	return strings.Contains(input.Header("Content-Type"), "multipart/form-data")
+}
+
+// AcceptsHTML Checks if request accepts html response
+func (input *BeegoInput) AcceptsHTML() bool {
+	return acceptsHTMLRegex.MatchString(input.Header("Accept"))
+}
+
+// AcceptsXML Checks if request accepts xml response
+func (input *BeegoInput) AcceptsXML() bool {
+	return acceptsXMLRegex.MatchString(input.Header("Accept"))
+}
+
+// AcceptsJSON Checks if request accepts json response
+func (input *BeegoInput) AcceptsJSON() bool {
+	return acceptsJSONRegex.MatchString(input.Header("Accept"))
+}
+
+// IP returns request client ip.
+// if in proxy, return first proxy id.
+// if error, return 127.0.0.1.
+func (input *BeegoInput) IP() string {
+	ips := input.Proxy()
+	if len(ips) > 0 && ips[0] != "" {
+		rip := strings.Split(ips[0], ":")
+		return rip[0]
+	}
+	ip := strings.Split(input.Context.Request.RemoteAddr, ":")
+	if len(ip) > 0 {
+		if ip[0] != "[" {
+			return ip[0]
+		}
+	}
+	return "127.0.0.1"
+}
+
+// Proxy returns proxy client ips slice.
+func (input *BeegoInput) Proxy() []string {
+	if ips := input.Header("X-Forwarded-For"); ips != "" {
+		return strings.Split(ips, ",")
+	}
+	return []string{}
+}
+
+// Referer returns http referer header.
+func (input *BeegoInput) Referer() string {
+	return input.Header("Referer")
+}
+
+// Refer returns http referer header.
+func (input *BeegoInput) Refer() string {
+	return input.Referer()
+}
+
+// SubDomains returns sub domain string.
+// if aa.bb.domain.com, returns aa.bb .
+func (input *BeegoInput) SubDomains() string {
+	parts := strings.Split(input.Host(), ".")
+	if len(parts) >= 3 {
+		return strings.Join(parts[:len(parts)-2], ".")
+	}
+	return ""
+}
+
+// Port returns request client port.
+// when error or empty, return 80.
+func (input *BeegoInput) Port() int {
+	parts := strings.Split(input.Context.Request.Host, ":")
+	if len(parts) == 2 {
+		port, _ := strconv.Atoi(parts[1])
+		return port
+	}
+	return 80
+}
+
+// UserAgent returns request client user agent string.
+func (input *BeegoInput) UserAgent() string {
+	return input.Header("User-Agent")
+}
+
+// ParamsLen return the length of the params
+func (input *BeegoInput) ParamsLen() int {
+	return len(input.pnames)
+}
+
+// Param returns router param by a given key.
+func (input *BeegoInput) Param(key string) string {
+	for i, v := range input.pnames {
+		if v == key && i <= len(input.pvalues) {
+			return input.pvalues[i]
+		}
+	}
+	return ""
+}
+
+// Params returns the map[key]value.
+func (input *BeegoInput) Params() map[string]string {
+	m := make(map[string]string)
+	for i, v := range input.pnames {
+		if i <= len(input.pvalues) {
+			m[v] = input.pvalues[i]
+		}
+	}
+	return m
+}
+
+// SetParam will set the param with key and value
+func (input *BeegoInput) SetParam(key, val string) {
+	// check if already exists
+	for i, v := range input.pnames {
+		if v == key && i <= len(input.pvalues) {
+			input.pvalues[i] = val
+			return
+		}
+	}
+	input.pvalues = append(input.pvalues, val)
+	input.pnames = append(input.pnames, key)
+}
+
+// ResetParams clears any of the input's Params
+// This function is used to clear parameters so they may be reset between filter
+// passes.
+func (input *BeegoInput) ResetParams() {
+	input.pnames = input.pnames[:0]
+	input.pvalues = input.pvalues[:0]
+}
+
+// Query returns input data item string by a given string.
+func (input *BeegoInput) Query(key string) string {
+	if val := input.Param(key); val != "" {
+		return val
+	}
+	if input.Context.Request.Form == nil {
+		input.Context.Request.ParseForm()
+	}
+	return input.Context.Request.Form.Get(key)
+}
+
+// Header returns request header item string by a given string.
+// if non-existed, return empty string.
+func (input *BeegoInput) Header(key string) string {
+	return input.Context.Request.Header.Get(key)
+}
+
+// Cookie returns request cookie item string by a given key.
+// if non-existed, return empty string.
+func (input *BeegoInput) Cookie(key string) string {
+	ck, err := input.Context.Request.Cookie(key)
+	if err != nil {
+		return ""
+	}
+	return ck.Value
+}
+
+// Session returns current session item value by a given key.
+// if non-existed, return nil.
+func (input *BeegoInput) Session(key interface{}) interface{} {
+	return input.CruSession.Get(key)
+}
+
+// CopyBody returns the raw request body data as bytes.
+func (input *BeegoInput) CopyBody(MaxMemory int64) []byte {
+	if input.Context.Request.Body == nil {
+		return []byte{}
+	}
+	safe := &io.LimitedReader{R: input.Context.Request.Body, N: MaxMemory}
+	requestbody, _ := ioutil.ReadAll(safe)
+	input.Context.Request.Body.Close()
+	bf := bytes.NewBuffer(requestbody)
+	input.Context.Request.Body = ioutil.NopCloser(bf)
+	input.RequestBody = requestbody
+	return requestbody
+}
+
+// Data return the implicit data in the input
+func (input *BeegoInput) Data() map[interface{}]interface{} {
+	if input.data == nil {
+		input.data = make(map[interface{}]interface{})
+	}
+	return input.data
+}
+
+// GetData returns the stored data in this context.
+func (input *BeegoInput) GetData(key interface{}) interface{} {
+	if v, ok := input.data[key]; ok {
+		return v
+	}
+	return nil
+}
+
+// SetData stores data with given key in this context.
+// This data are only available in this context.
+func (input *BeegoInput) SetData(key, val interface{}) {
+	if input.data == nil {
+		input.data = make(map[interface{}]interface{})
+	}
+	input.data[key] = val
+}
+
+// ParseFormOrMulitForm parseForm or parseMultiForm based on Content-type
+func (input *BeegoInput) ParseFormOrMulitForm(maxMemory int64) error {
+	// Parse the body depending on the content type.
+	if strings.Contains(input.Header("Content-Type"), "multipart/form-data") {
+		if err := input.Context.Request.ParseMultipartForm(maxMemory); err != nil {
+			return errors.New("Error parsing request body:" + err.Error())
+		}
+	} else if err := input.Context.Request.ParseForm(); err != nil {
+		return errors.New("Error parsing request body:" + err.Error())
+	}
+	return nil
+}
+
+// Bind data from request.Form[key] to dest
+// like /?id=123&isok=true&ft=1.2&ol[0]=1&ol[1]=2&ul[]=str&ul[]=array&user.Name=astaxie
+// var id int  beegoInput.Bind(&id, "id")  id ==123
+// var isok bool  beegoInput.Bind(&isok, "isok")  isok ==true
+// var ft float64  beegoInput.Bind(&ft, "ft")  ft ==1.2
+// ol := make([]int, 0, 2)  beegoInput.Bind(&ol, "ol")  ol ==[1 2]
+// ul := make([]string, 0, 2)  beegoInput.Bind(&ul, "ul")  ul ==[str array]
+// user struct{Name}  beegoInput.Bind(&user, "user")  user == {Name:"astaxie"}
+func (input *BeegoInput) Bind(dest interface{}, key string) error {
+	value := reflect.ValueOf(dest)
+	if value.Kind() != reflect.Ptr {
+		return errors.New("beego: non-pointer passed to Bind: " + key)
+	}
+	value = value.Elem()
+	if !value.CanSet() {
+		return errors.New("beego: non-settable variable passed to Bind: " + key)
+	}
+	typ := value.Type()
+	// Get real type if dest define with interface{}.
+	// e.g  var dest interface{} dest=1.0
+	if value.Kind() == reflect.Interface {
+		typ = value.Elem().Type()
+	}
+	rv := input.bind(key, typ)
+	if !rv.IsValid() {
+		return errors.New("beego: reflect value is empty")
+	}
+	value.Set(rv)
+	return nil
+}
+
+func (input *BeegoInput) bind(key string, typ reflect.Type) reflect.Value {
+	if input.Context.Request.Form == nil {
+		input.Context.Request.ParseForm()
+	}
+	rv := reflect.Zero(typ)
+	switch typ.Kind() {
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		val := input.Query(key)
+		if len(val) == 0 {
+			return rv
+		}
+		rv = input.bindInt(val, typ)
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+		val := input.Query(key)
+		if len(val) == 0 {
+			return rv
+		}
+		rv = input.bindUint(val, typ)
+	case reflect.Float32, reflect.Float64:
+		val := input.Query(key)
+		if len(val) == 0 {
+			return rv
+		}
+		rv = input.bindFloat(val, typ)
+	case reflect.String:
+		val := input.Query(key)
+		if len(val) == 0 {
+			return rv
+		}
+		rv = input.bindString(val, typ)
+	case reflect.Bool:
+		val := input.Query(key)
+		if len(val) == 0 {
+			return rv
+		}
+		rv = input.bindBool(val, typ)
+	case reflect.Slice:
+		rv = input.bindSlice(&input.Context.Request.Form, key, typ)
+	case reflect.Struct:
+		rv = input.bindStruct(&input.Context.Request.Form, key, typ)
+	case reflect.Ptr:
+		rv = input.bindPoint(key, typ)
+	case reflect.Map:
+		rv = input.bindMap(&input.Context.Request.Form, key, typ)
+	}
+	return rv
+}
+
+func (input *BeegoInput) bindValue(val string, typ reflect.Type) reflect.Value {
+	rv := reflect.Zero(typ)
+	switch typ.Kind() {
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		rv = input.bindInt(val, typ)
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+		rv = input.bindUint(val, typ)
+	case reflect.Float32, reflect.Float64:
+		rv = input.bindFloat(val, typ)
+	case reflect.String:
+		rv = input.bindString(val, typ)
+	case reflect.Bool:
+		rv = input.bindBool(val, typ)
+	case reflect.Slice:
+		rv = input.bindSlice(&url.Values{"": {val}}, "", typ)
+	case reflect.Struct:
+		rv = input.bindStruct(&url.Values{"": {val}}, "", typ)
+	case reflect.Ptr:
+		rv = input.bindPoint(val, typ)
+	case reflect.Map:
+		rv = input.bindMap(&url.Values{"": {val}}, "", typ)
+	}
+	return rv
+}
+
+func (input *BeegoInput) bindInt(val string, typ reflect.Type) reflect.Value {
+	intValue, err := strconv.ParseInt(val, 10, 64)
+	if err != nil {
+		return reflect.Zero(typ)
+	}
+	pValue := reflect.New(typ)
+	pValue.Elem().SetInt(intValue)
+	return pValue.Elem()
+}
+
+func (input *BeegoInput) bindUint(val string, typ reflect.Type) reflect.Value {
+	uintValue, err := strconv.ParseUint(val, 10, 64)
+	if err != nil {
+		return reflect.Zero(typ)
+	}
+	pValue := reflect.New(typ)
+	pValue.Elem().SetUint(uintValue)
+	return pValue.Elem()
+}
+
+func (input *BeegoInput) bindFloat(val string, typ reflect.Type) reflect.Value {
+	floatValue, err := strconv.ParseFloat(val, 64)
+	if err != nil {
+		return reflect.Zero(typ)
+	}
+	pValue := reflect.New(typ)
+	pValue.Elem().SetFloat(floatValue)
+	return pValue.Elem()
+}
+
+func (input *BeegoInput) bindString(val string, typ reflect.Type) reflect.Value {
+	return reflect.ValueOf(val)
+}
+
+func (input *BeegoInput) bindBool(val string, typ reflect.Type) reflect.Value {
+	val = strings.TrimSpace(strings.ToLower(val))
+	switch val {
+	case "true", "on", "1":
+		return reflect.ValueOf(true)
+	}
+	return reflect.ValueOf(false)
+}
+
+type sliceValue struct {
+	index int           // Index extracted from brackets.  If -1, no index was provided.
+	value reflect.Value // the bound value for this slice element.
+}
+
+func (input *BeegoInput) bindSlice(params *url.Values, key string, typ reflect.Type) reflect.Value {
+	maxIndex := -1
+	numNoIndex := 0
+	sliceValues := []sliceValue{}
+	for reqKey, vals := range *params {
+		if !strings.HasPrefix(reqKey, key+"[") {
+			continue
+		}
+		// Extract the index, and the index where a sub-key starts. (e.g. field[0].subkey)
+		index := -1
+		leftBracket, rightBracket := len(key), strings.Index(reqKey[len(key):], "]")+len(key)
+		if rightBracket > leftBracket+1 {
+			index, _ = strconv.Atoi(reqKey[leftBracket+1 : rightBracket])
+		}
+		subKeyIndex := rightBracket + 1
+
+		// Handle the indexed case.
+		if index > -1 {
+			if index > maxIndex {
+				maxIndex = index
+			}
+			sliceValues = append(sliceValues, sliceValue{
+				index: index,
+				value: input.bind(reqKey[:subKeyIndex], typ.Elem()),
+			})
+			continue
+		}
+
+		// It's an un-indexed element.  (e.g. element[])
+		numNoIndex += len(vals)
+		for _, val := range vals {
+			// Unindexed values can only be direct-bound.
+			sliceValues = append(sliceValues, sliceValue{
+				index: -1,
+				value: input.bindValue(val, typ.Elem()),
+			})
+		}
+	}
+	resultArray := reflect.MakeSlice(typ, maxIndex+1, maxIndex+1+numNoIndex)
+	for _, sv := range sliceValues {
+		if sv.index != -1 {
+			resultArray.Index(sv.index).Set(sv.value)
+		} else {
+			resultArray = reflect.Append(resultArray, sv.value)
+		}
+	}
+	return resultArray
+}
+
+func (input *BeegoInput) bindStruct(params *url.Values, key string, typ reflect.Type) reflect.Value {
+	result := reflect.New(typ).Elem()
+	fieldValues := make(map[string]reflect.Value)
+	for reqKey, val := range *params {
+		var fieldName string
+		if strings.HasPrefix(reqKey, key+".") {
+			fieldName = reqKey[len(key)+1:]
+		} else if strings.HasPrefix(reqKey, key+"[") && reqKey[len(reqKey)-1] == ']' {
+			fieldName = reqKey[len(key)+1 : len(reqKey)-1]
+		} else {
+			continue
+		}
+
+		if _, ok := fieldValues[fieldName]; !ok {
+			// Time to bind this field.  Get it and make sure we can set it.
+			fieldValue := result.FieldByName(fieldName)
+			if !fieldValue.IsValid() {
+				continue
+			}
+			if !fieldValue.CanSet() {
+				continue
+			}
+			boundVal := input.bindValue(val[0], fieldValue.Type())
+			fieldValue.Set(boundVal)
+			fieldValues[fieldName] = boundVal
+		}
+	}
+
+	return result
+}
+
+func (input *BeegoInput) bindPoint(key string, typ reflect.Type) reflect.Value {
+	return input.bind(key, typ.Elem()).Addr()
+}
+
+func (input *BeegoInput) bindMap(params *url.Values, key string, typ reflect.Type) reflect.Value {
+	var (
+		result    = reflect.MakeMap(typ)
+		keyType   = typ.Key()
+		valueType = typ.Elem()
+	)
+	for paramName, values := range *params {
+		if !strings.HasPrefix(paramName, key+"[") || paramName[len(paramName)-1] != ']' {
+			continue
+		}
+
+		key := paramName[len(key)+1 : len(paramName)-1]
+		result.SetMapIndex(input.bindValue(key, keyType), input.bindValue(values[0], valueType))
+	}
+	return result
+}

+ 207 - 0
vendor/github.com/fatedier/beego/context/input_test.go

@@ -0,0 +1,207 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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 context
+
+import (
+	"net/http"
+	"net/http/httptest"
+	"reflect"
+	"testing"
+)
+
+func TestBind(t *testing.T) {
+	type testItem struct {
+		field string
+		empty interface{}
+		want  interface{}
+	}
+	type Human struct {
+		ID   int
+		Nick string
+		Pwd  string
+		Ms   bool
+	}
+
+	cases := []struct {
+		request string
+		valueGp []testItem
+	}{
+		{"/?p=str", []testItem{{"p", interface{}(""), interface{}("str")}}},
+
+		{"/?p=", []testItem{{"p", "", ""}}},
+		{"/?p=str", []testItem{{"p", "", "str"}}},
+
+		{"/?p=123", []testItem{{"p", 0, 123}}},
+		{"/?p=123", []testItem{{"p", uint(0), uint(123)}}},
+
+		{"/?p=1.0", []testItem{{"p", 0.0, 1.0}}},
+		{"/?p=1", []testItem{{"p", false, true}}},
+
+		{"/?p=true", []testItem{{"p", false, true}}},
+		{"/?p=ON", []testItem{{"p", false, true}}},
+		{"/?p=on", []testItem{{"p", false, true}}},
+		{"/?p=1", []testItem{{"p", false, true}}},
+		{"/?p=2", []testItem{{"p", false, false}}},
+		{"/?p=false", []testItem{{"p", false, false}}},
+
+		{"/?p[a]=1&p[b]=2&p[c]=3", []testItem{{"p", map[string]int{}, map[string]int{"a": 1, "b": 2, "c": 3}}}},
+		{"/?p[a]=v1&p[b]=v2&p[c]=v3", []testItem{{"p", map[string]string{}, map[string]string{"a": "v1", "b": "v2", "c": "v3"}}}},
+
+		{"/?p[]=8&p[]=9&p[]=10", []testItem{{"p", []int{}, []int{8, 9, 10}}}},
+		{"/?p[0]=8&p[1]=9&p[2]=10", []testItem{{"p", []int{}, []int{8, 9, 10}}}},
+		{"/?p[0]=8&p[1]=9&p[2]=10&p[5]=14", []testItem{{"p", []int{}, []int{8, 9, 10, 0, 0, 14}}}},
+		{"/?p[0]=8.0&p[1]=9.0&p[2]=10.0", []testItem{{"p", []float64{}, []float64{8.0, 9.0, 10.0}}}},
+
+		{"/?p[]=10&p[]=9&p[]=8", []testItem{{"p", []string{}, []string{"10", "9", "8"}}}},
+		{"/?p[0]=8&p[1]=9&p[2]=10", []testItem{{"p", []string{}, []string{"8", "9", "10"}}}},
+
+		{"/?p[0]=true&p[1]=false&p[2]=true&p[5]=1&p[6]=ON&p[7]=other", []testItem{{"p", []bool{}, []bool{true, false, true, false, false, true, true, false}}}},
+
+		{"/?human.Nick=astaxie", []testItem{{"human", Human{}, Human{Nick: "astaxie"}}}},
+		{"/?human.ID=888&human.Nick=astaxie&human.Ms=true&human[Pwd]=pass", []testItem{{"human", Human{}, Human{ID: 888, Nick: "astaxie", Ms: true, Pwd: "pass"}}}},
+		{"/?human[0].ID=888&human[0].Nick=astaxie&human[0].Ms=true&human[0][Pwd]=pass01&human[1].ID=999&human[1].Nick=ysqi&human[1].Ms=On&human[1].Pwd=pass02",
+			[]testItem{{"human", []Human{}, []Human{
+				Human{ID: 888, Nick: "astaxie", Ms: true, Pwd: "pass01"},
+				Human{ID: 999, Nick: "ysqi", Ms: true, Pwd: "pass02"},
+			}}}},
+
+		{
+			"/?id=123&isok=true&ft=1.2&ol[0]=1&ol[1]=2&ul[]=str&ul[]=array&human.Nick=astaxie",
+			[]testItem{
+				{"id", 0, 123},
+				{"isok", false, true},
+				{"ft", 0.0, 1.2},
+				{"ol", []int{}, []int{1, 2}},
+				{"ul", []string{}, []string{"str", "array"}},
+				{"human", Human{}, Human{Nick: "astaxie"}},
+			},
+		},
+	}
+	for _, c := range cases {
+		r, _ := http.NewRequest("GET", c.request, nil)
+		beegoInput := NewInput()
+		beegoInput.Context = NewContext()
+		beegoInput.Context.Reset(httptest.NewRecorder(), r)
+
+		for _, item := range c.valueGp {
+			got := item.empty
+			err := beegoInput.Bind(&got, item.field)
+			if err != nil {
+				t.Fatal(err)
+			}
+			if !reflect.DeepEqual(got, item.want) {
+				t.Fatalf("Bind %q error,should be:\n%#v \ngot:\n%#v", item.field, item.want, got)
+			}
+		}
+
+	}
+}
+
+func TestSubDomain(t *testing.T) {
+	r, _ := http.NewRequest("GET", "http://www.example.com/?id=123&isok=true&ft=1.2&ol[0]=1&ol[1]=2&ul[]=str&ul[]=array&user.Name=astaxie", nil)
+	beegoInput := NewInput()
+	beegoInput.Context = NewContext()
+	beegoInput.Context.Reset(httptest.NewRecorder(), r)
+
+	subdomain := beegoInput.SubDomains()
+	if subdomain != "www" {
+		t.Fatal("Subdomain parse error, got" + subdomain)
+	}
+
+	r, _ = http.NewRequest("GET", "http://localhost/", nil)
+	beegoInput.Context.Request = r
+	if beegoInput.SubDomains() != "" {
+		t.Fatal("Subdomain parse error, should be empty, got " + beegoInput.SubDomains())
+	}
+
+	r, _ = http.NewRequest("GET", "http://aa.bb.example.com/", nil)
+	beegoInput.Context.Request = r
+	if beegoInput.SubDomains() != "aa.bb" {
+		t.Fatal("Subdomain parse error, got " + beegoInput.SubDomains())
+	}
+
+	/* TODO Fix this
+	r, _ = http.NewRequest("GET", "http://127.0.0.1/", nil)
+	beegoInput.Context.Request = r
+	if beegoInput.SubDomains() != "" {
+		t.Fatal("Subdomain parse error, got " + beegoInput.SubDomains())
+	}
+	*/
+
+	r, _ = http.NewRequest("GET", "http://example.com/", nil)
+	beegoInput.Context.Request = r
+	if beegoInput.SubDomains() != "" {
+		t.Fatal("Subdomain parse error, got " + beegoInput.SubDomains())
+	}
+
+	r, _ = http.NewRequest("GET", "http://aa.bb.cc.dd.example.com/", nil)
+	beegoInput.Context.Request = r
+	if beegoInput.SubDomains() != "aa.bb.cc.dd" {
+		t.Fatal("Subdomain parse error, got " + beegoInput.SubDomains())
+	}
+}
+
+func TestParams(t *testing.T) {
+	inp := NewInput()
+
+	inp.SetParam("p1", "val1_ver1")
+	inp.SetParam("p2", "val2_ver1")
+	inp.SetParam("p3", "val3_ver1")
+	if l := inp.ParamsLen(); l != 3 {
+		t.Fatalf("Input.ParamsLen wrong value: %d, expected %d", l, 3)
+	}
+
+	if val := inp.Param("p1"); val != "val1_ver1" {
+		t.Fatalf("Input.Param wrong value: %s, expected %s", val, "val1_ver1")
+	}
+	if val := inp.Param("p3"); val != "val3_ver1" {
+		t.Fatalf("Input.Param wrong value: %s, expected %s", val, "val3_ver1")
+	}
+	vals := inp.Params()
+	expected := map[string]string{
+		"p1": "val1_ver1",
+		"p2": "val2_ver1",
+		"p3": "val3_ver1",
+	}
+	if !reflect.DeepEqual(vals, expected) {
+		t.Fatalf("Input.Params wrong value: %s, expected %s", vals, expected)
+	}
+
+	// overwriting existing params
+	inp.SetParam("p1", "val1_ver2")
+	inp.SetParam("p2", "val2_ver2")
+	expected = map[string]string{
+		"p1": "val1_ver2",
+		"p2": "val2_ver2",
+		"p3": "val3_ver1",
+	}
+	vals = inp.Params()
+	if !reflect.DeepEqual(vals, expected) {
+		t.Fatalf("Input.Params wrong value: %s, expected %s", vals, expected)
+	}
+
+	if l := inp.ParamsLen(); l != 3 {
+		t.Fatalf("Input.ParamsLen wrong value: %d, expected %d", l, 3)
+	}
+
+	if val := inp.Param("p1"); val != "val1_ver2" {
+		t.Fatalf("Input.Param wrong value: %s, expected %s", val, "val1_ver2")
+	}
+
+	if val := inp.Param("p2"); val != "val2_ver2" {
+		t.Fatalf("Input.Param wrong value: %s, expected %s", val, "val1_ver2")
+	}
+
+}

+ 350 - 0
vendor/github.com/fatedier/beego/context/output.go

@@ -0,0 +1,350 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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 context
+
+import (
+	"bytes"
+	"encoding/json"
+	"encoding/xml"
+	"errors"
+	"fmt"
+	"html/template"
+	"io"
+	"mime"
+	"net/http"
+	"net/url"
+	"os"
+	"path/filepath"
+	"strconv"
+	"strings"
+	"time"
+)
+
+// BeegoOutput does work for sending response header.
+type BeegoOutput struct {
+	Context    *Context
+	Status     int
+	EnableGzip bool
+}
+
+// NewOutput returns new BeegoOutput.
+// it contains nothing now.
+func NewOutput() *BeegoOutput {
+	return &BeegoOutput{}
+}
+
+// Reset init BeegoOutput
+func (output *BeegoOutput) Reset(ctx *Context) {
+	output.Context = ctx
+	output.Status = 0
+}
+
+// Header sets response header item string via given key.
+func (output *BeegoOutput) Header(key, val string) {
+	output.Context.ResponseWriter.Header().Set(key, val)
+}
+
+// Body sets response body content.
+// if EnableGzip, compress content string.
+// it sends out response body directly.
+func (output *BeegoOutput) Body(content []byte) error {
+	var encoding string
+	var buf = &bytes.Buffer{}
+	if output.EnableGzip {
+		encoding = ParseEncoding(output.Context.Request)
+	}
+	if b, n, _ := WriteBody(encoding, buf, content); b {
+		output.Header("Content-Encoding", n)
+		output.Header("Content-Length", strconv.Itoa(buf.Len()))
+	} else {
+		output.Header("Content-Length", strconv.Itoa(len(content)))
+	}
+	// Write status code if it has been set manually
+	// Set it to 0 afterwards to prevent "multiple response.WriteHeader calls"
+	if output.Status != 0 {
+		output.Context.ResponseWriter.WriteHeader(output.Status)
+		output.Status = 0
+	} else {
+		output.Context.ResponseWriter.Started = true
+	}
+	io.Copy(output.Context.ResponseWriter, buf)
+	return nil
+}
+
+// Cookie sets cookie value via given key.
+// others are ordered as cookie's max age time, path,domain, secure and httponly.
+func (output *BeegoOutput) Cookie(name string, value string, others ...interface{}) {
+	var b bytes.Buffer
+	fmt.Fprintf(&b, "%s=%s", sanitizeName(name), sanitizeValue(value))
+
+	//fix cookie not work in IE
+	if len(others) > 0 {
+		var maxAge int64
+
+		switch v := others[0].(type) {
+		case int:
+			maxAge = int64(v)
+		case int32:
+			maxAge = int64(v)
+		case int64:
+			maxAge = v
+		}
+
+		switch {
+		case maxAge > 0:
+			fmt.Fprintf(&b, "; Expires=%s; Max-Age=%d", time.Now().Add(time.Duration(maxAge)*time.Second).UTC().Format(time.RFC1123), maxAge)
+		case maxAge < 0:
+			fmt.Fprintf(&b, "; Max-Age=0")
+		}
+	}
+
+	// the settings below
+	// Path, Domain, Secure, HttpOnly
+	// can use nil skip set
+
+	// default "/"
+	if len(others) > 1 {
+		if v, ok := others[1].(string); ok && len(v) > 0 {
+			fmt.Fprintf(&b, "; Path=%s", sanitizeValue(v))
+		}
+	} else {
+		fmt.Fprintf(&b, "; Path=%s", "/")
+	}
+
+	// default empty
+	if len(others) > 2 {
+		if v, ok := others[2].(string); ok && len(v) > 0 {
+			fmt.Fprintf(&b, "; Domain=%s", sanitizeValue(v))
+		}
+	}
+
+	// default empty
+	if len(others) > 3 {
+		var secure bool
+		switch v := others[3].(type) {
+		case bool:
+			secure = v
+		default:
+			if others[3] != nil {
+				secure = true
+			}
+		}
+		if secure {
+			fmt.Fprintf(&b, "; Secure")
+		}
+	}
+
+	// default false. for session cookie default true
+	if len(others) > 4 {
+		if v, ok := others[4].(bool); ok && v {
+			fmt.Fprintf(&b, "; HttpOnly")
+		}
+	}
+
+	output.Context.ResponseWriter.Header().Add("Set-Cookie", b.String())
+}
+
+var cookieNameSanitizer = strings.NewReplacer("\n", "-", "\r", "-")
+
+func sanitizeName(n string) string {
+	return cookieNameSanitizer.Replace(n)
+}
+
+var cookieValueSanitizer = strings.NewReplacer("\n", " ", "\r", " ", ";", " ")
+
+func sanitizeValue(v string) string {
+	return cookieValueSanitizer.Replace(v)
+}
+
+// JSON writes json to response body.
+// if coding is true, it converts utf-8 to \u0000 type.
+func (output *BeegoOutput) JSON(data interface{}, hasIndent bool, coding bool) error {
+	output.Header("Content-Type", "application/json; charset=utf-8")
+	var content []byte
+	var err error
+	if hasIndent {
+		content, err = json.MarshalIndent(data, "", "  ")
+	} else {
+		content, err = json.Marshal(data)
+	}
+	if err != nil {
+		http.Error(output.Context.ResponseWriter, err.Error(), http.StatusInternalServerError)
+		return err
+	}
+	if coding {
+		content = []byte(stringsToJSON(string(content)))
+	}
+	return output.Body(content)
+}
+
+// JSONP writes jsonp to response body.
+func (output *BeegoOutput) JSONP(data interface{}, hasIndent bool) error {
+	output.Header("Content-Type", "application/javascript; charset=utf-8")
+	var content []byte
+	var err error
+	if hasIndent {
+		content, err = json.MarshalIndent(data, "", "  ")
+	} else {
+		content, err = json.Marshal(data)
+	}
+	if err != nil {
+		http.Error(output.Context.ResponseWriter, err.Error(), http.StatusInternalServerError)
+		return err
+	}
+	callback := output.Context.Input.Query("callback")
+	if callback == "" {
+		return errors.New(`"callback" parameter required`)
+	}
+	callback = template.JSEscapeString(callback)
+	callbackContent := bytes.NewBufferString(" if(window." + callback + ")" + callback)
+	callbackContent.WriteString("(")
+	callbackContent.Write(content)
+	callbackContent.WriteString(");\r\n")
+	return output.Body(callbackContent.Bytes())
+}
+
+// XML writes xml string to response body.
+func (output *BeegoOutput) XML(data interface{}, hasIndent bool) error {
+	output.Header("Content-Type", "application/xml; charset=utf-8")
+	var content []byte
+	var err error
+	if hasIndent {
+		content, err = xml.MarshalIndent(data, "", "  ")
+	} else {
+		content, err = xml.Marshal(data)
+	}
+	if err != nil {
+		http.Error(output.Context.ResponseWriter, err.Error(), http.StatusInternalServerError)
+		return err
+	}
+	return output.Body(content)
+}
+
+// Download forces response for download file.
+// it prepares the download response header automatically.
+func (output *BeegoOutput) Download(file string, filename ...string) {
+	// check get file error, file not found or other error.
+	if _, err := os.Stat(file); err != nil {
+		http.ServeFile(output.Context.ResponseWriter, output.Context.Request, file)
+		return
+	}
+
+	var fName string
+	if len(filename) > 0 && filename[0] != "" {
+		fName = filename[0]
+	} else {
+		fName = filepath.Base(file)
+	}
+	output.Header("Content-Disposition", "attachment; filename="+url.QueryEscape(fName))
+	output.Header("Content-Description", "File Transfer")
+	output.Header("Content-Type", "application/octet-stream")
+	output.Header("Content-Transfer-Encoding", "binary")
+	output.Header("Expires", "0")
+	output.Header("Cache-Control", "must-revalidate")
+	output.Header("Pragma", "public")
+	http.ServeFile(output.Context.ResponseWriter, output.Context.Request, file)
+}
+
+// ContentType sets the content type from ext string.
+// MIME type is given in mime package.
+func (output *BeegoOutput) ContentType(ext string) {
+	if !strings.HasPrefix(ext, ".") {
+		ext = "." + ext
+	}
+	ctype := mime.TypeByExtension(ext)
+	if ctype != "" {
+		output.Header("Content-Type", ctype)
+	}
+}
+
+// SetStatus sets response status code.
+// It writes response header directly.
+func (output *BeegoOutput) SetStatus(status int) {
+	output.Status = status
+}
+
+// IsCachable returns boolean of this request is cached.
+// HTTP 304 means cached.
+func (output *BeegoOutput) IsCachable() bool {
+	return output.Status >= 200 && output.Status < 300 || output.Status == 304
+}
+
+// IsEmpty returns boolean of this request is empty.
+// HTTP 201,204 and 304 means empty.
+func (output *BeegoOutput) IsEmpty() bool {
+	return output.Status == 201 || output.Status == 204 || output.Status == 304
+}
+
+// IsOk returns boolean of this request runs well.
+// HTTP 200 means ok.
+func (output *BeegoOutput) IsOk() bool {
+	return output.Status == 200
+}
+
+// IsSuccessful returns boolean of this request runs successfully.
+// HTTP 2xx means ok.
+func (output *BeegoOutput) IsSuccessful() bool {
+	return output.Status >= 200 && output.Status < 300
+}
+
+// IsRedirect returns boolean of this request is redirection header.
+// HTTP 301,302,307 means redirection.
+func (output *BeegoOutput) IsRedirect() bool {
+	return output.Status == 301 || output.Status == 302 || output.Status == 303 || output.Status == 307
+}
+
+// IsForbidden returns boolean of this request is forbidden.
+// HTTP 403 means forbidden.
+func (output *BeegoOutput) IsForbidden() bool {
+	return output.Status == 403
+}
+
+// IsNotFound returns boolean of this request is not found.
+// HTTP 404 means forbidden.
+func (output *BeegoOutput) IsNotFound() bool {
+	return output.Status == 404
+}
+
+// IsClientError returns boolean of this request client sends error data.
+// HTTP 4xx means forbidden.
+func (output *BeegoOutput) IsClientError() bool {
+	return output.Status >= 400 && output.Status < 500
+}
+
+// IsServerError returns boolean of this server handler errors.
+// HTTP 5xx means server internal error.
+func (output *BeegoOutput) IsServerError() bool {
+	return output.Status >= 500 && output.Status < 600
+}
+
+func stringsToJSON(str string) string {
+	rs := []rune(str)
+	var jsons bytes.Buffer
+	for _, r := range rs {
+		rint := int(r)
+		if rint < 128 {
+			jsons.WriteRune(r)
+		} else {
+			jsons.WriteString("\\u")
+			jsons.WriteString(strconv.FormatInt(int64(rint), 16))
+		}
+	}
+	return jsons.String()
+}
+
+// Session sets session item value with given key.
+func (output *BeegoOutput) Session(name interface{}, value interface{}) {
+	output.Context.Input.CruSession.Set(name, value)
+}

+ 652 - 0
vendor/github.com/fatedier/beego/controller.go

@@ -0,0 +1,652 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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 beego
+
+import (
+	"bytes"
+	"errors"
+	"html/template"
+	"io"
+	"mime/multipart"
+	"net/http"
+	"net/url"
+	"os"
+	"reflect"
+	"strconv"
+	"strings"
+
+	"github.com/astaxie/beego/context"
+	"github.com/astaxie/beego/session"
+)
+
+//commonly used mime-types
+const (
+	applicationJSON = "application/json"
+	applicationXML  = "application/xml"
+	textXML         = "text/xml"
+)
+
+var (
+	// ErrAbort custom error when user stop request handler manually.
+	ErrAbort = errors.New("User stop run")
+	// GlobalControllerRouter store comments with controller. pkgpath+controller:comments
+	GlobalControllerRouter = make(map[string][]ControllerComments)
+)
+
+// ControllerComments store the comment for the controller method
+type ControllerComments struct {
+	Method           string
+	Router           string
+	AllowHTTPMethods []string
+	Params           []map[string]string
+}
+
+// Controller defines some basic http request handler operations, such as
+// http context, template and view, session and xsrf.
+type Controller struct {
+	// context data
+	Ctx  *context.Context
+	Data map[interface{}]interface{}
+
+	// route controller info
+	controllerName string
+	actionName     string
+	methodMapping  map[string]func() //method:routertree
+	gotofunc       string
+	AppController  interface{}
+
+	// template data
+	TplName        string
+	ViewPath       string
+	Layout         string
+	LayoutSections map[string]string // the key is the section name and the value is the template name
+	TplPrefix      string
+	TplExt         string
+	EnableRender   bool
+
+	// xsrf data
+	_xsrfToken string
+	XSRFExpire int
+	EnableXSRF bool
+
+	// session
+	CruSession session.Store
+}
+
+// ControllerInterface is an interface to uniform all controller handler.
+type ControllerInterface interface {
+	Init(ct *context.Context, controllerName, actionName string, app interface{})
+	Prepare()
+	Get()
+	Post()
+	Delete()
+	Put()
+	Head()
+	Patch()
+	Options()
+	Finish()
+	Render() error
+	XSRFToken() string
+	CheckXSRFCookie() bool
+	HandlerFunc(fn string) bool
+	URLMapping()
+}
+
+// Init generates default values of controller operations.
+func (c *Controller) Init(ctx *context.Context, controllerName, actionName string, app interface{}) {
+	c.Layout = ""
+	c.TplName = ""
+	c.controllerName = controllerName
+	c.actionName = actionName
+	c.Ctx = ctx
+	c.TplExt = "tpl"
+	c.AppController = app
+	c.EnableRender = true
+	c.EnableXSRF = true
+	c.Data = ctx.Input.Data()
+	c.methodMapping = make(map[string]func())
+}
+
+// Prepare runs after Init before request function execution.
+func (c *Controller) Prepare() {}
+
+// Finish runs after request function execution.
+func (c *Controller) Finish() {}
+
+// Get adds a request function to handle GET request.
+func (c *Controller) Get() {
+	http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", 405)
+}
+
+// Post adds a request function to handle POST request.
+func (c *Controller) Post() {
+	http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", 405)
+}
+
+// Delete adds a request function to handle DELETE request.
+func (c *Controller) Delete() {
+	http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", 405)
+}
+
+// Put adds a request function to handle PUT request.
+func (c *Controller) Put() {
+	http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", 405)
+}
+
+// Head adds a request function to handle HEAD request.
+func (c *Controller) Head() {
+	http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", 405)
+}
+
+// Patch adds a request function to handle PATCH request.
+func (c *Controller) Patch() {
+	http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", 405)
+}
+
+// Options adds a request function to handle OPTIONS request.
+func (c *Controller) Options() {
+	http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", 405)
+}
+
+// HandlerFunc call function with the name
+func (c *Controller) HandlerFunc(fnname string) bool {
+	if v, ok := c.methodMapping[fnname]; ok {
+		v()
+		return true
+	}
+	return false
+}
+
+// URLMapping register the internal Controller router.
+func (c *Controller) URLMapping() {}
+
+// Mapping the method to function
+func (c *Controller) Mapping(method string, fn func()) {
+	c.methodMapping[method] = fn
+}
+
+// Render sends the response with rendered template bytes as text/html type.
+func (c *Controller) Render() error {
+	if !c.EnableRender {
+		return nil
+	}
+	rb, err := c.RenderBytes()
+	if err != nil {
+		return err
+	}
+
+	if c.Ctx.ResponseWriter.Header().Get("Content-Type") == "" {
+		c.Ctx.Output.Header("Content-Type", "text/html; charset=utf-8")
+	}
+
+	return c.Ctx.Output.Body(rb)
+}
+
+// RenderString returns the rendered template string. Do not send out response.
+func (c *Controller) RenderString() (string, error) {
+	b, e := c.RenderBytes()
+	return string(b), e
+}
+
+// RenderBytes returns the bytes of rendered template string. Do not send out response.
+func (c *Controller) RenderBytes() ([]byte, error) {
+	buf, err := c.renderTemplate()
+	//if the controller has set layout, then first get the tplName's content set the content to the layout
+	if err == nil && c.Layout != "" {
+		c.Data["LayoutContent"] = template.HTML(buf.String())
+
+		if c.LayoutSections != nil {
+			for sectionName, sectionTpl := range c.LayoutSections {
+				if sectionTpl == "" {
+					c.Data[sectionName] = ""
+					continue
+				}
+				buf.Reset()
+				err = ExecuteViewPathTemplate(&buf, sectionTpl, c.viewPath(), c.Data)
+				if err != nil {
+					return nil, err
+				}
+				c.Data[sectionName] = template.HTML(buf.String())
+			}
+		}
+
+		buf.Reset()
+		ExecuteViewPathTemplate(&buf, c.Layout, c.viewPath() ,c.Data)
+	}
+	return buf.Bytes(), err
+}
+
+func (c *Controller) renderTemplate() (bytes.Buffer, error) {
+	var buf bytes.Buffer
+	if c.TplName == "" {
+		c.TplName = strings.ToLower(c.controllerName) + "/" + strings.ToLower(c.actionName) + "." + c.TplExt
+	}
+	if c.TplPrefix != "" {
+		c.TplName = c.TplPrefix + c.TplName
+	}
+	if BConfig.RunMode == DEV {
+		buildFiles := []string{c.TplName}
+		if c.Layout != "" {
+			buildFiles = append(buildFiles, c.Layout)
+			if c.LayoutSections != nil {
+				for _, sectionTpl := range c.LayoutSections {
+					if sectionTpl == "" {
+						continue
+					}
+					buildFiles = append(buildFiles, sectionTpl)
+				}
+			}
+		}
+		BuildTemplate(c.viewPath() , buildFiles...)
+	}
+	return buf, ExecuteViewPathTemplate(&buf, c.TplName, c.viewPath(), c.Data)
+}
+
+func (c *Controller) viewPath() string {
+	if c.ViewPath == "" {
+		return BConfig.WebConfig.ViewsPath
+	}
+	return c.ViewPath
+}
+
+// Redirect sends the redirection response to url with status code.
+func (c *Controller) Redirect(url string, code int) {
+	c.Ctx.Redirect(code, url)
+}
+
+// Abort stops controller handler and show the error data if code is defined in ErrorMap or code string.
+func (c *Controller) Abort(code string) {
+	status, err := strconv.Atoi(code)
+	if err != nil {
+		status = 200
+	}
+	c.CustomAbort(status, code)
+}
+
+// CustomAbort stops controller handler and show the error data, it's similar Aborts, but support status code and body.
+func (c *Controller) CustomAbort(status int, body string) {
+	// first panic from ErrorMaps, it is user defined error functions.
+	if _, ok := ErrorMaps[body]; ok {
+		c.Ctx.Output.Status = status
+		panic(body)
+	}
+	// last panic user string
+	c.Ctx.ResponseWriter.WriteHeader(status)
+	c.Ctx.ResponseWriter.Write([]byte(body))
+	panic(ErrAbort)
+}
+
+// StopRun makes panic of USERSTOPRUN error and go to recover function if defined.
+func (c *Controller) StopRun() {
+	panic(ErrAbort)
+}
+
+// URLFor does another controller handler in this request function.
+// it goes to this controller method if endpoint is not clear.
+func (c *Controller) URLFor(endpoint string, values ...interface{}) string {
+	if len(endpoint) == 0 {
+		return ""
+	}
+	if endpoint[0] == '.' {
+		return URLFor(reflect.Indirect(reflect.ValueOf(c.AppController)).Type().Name()+endpoint, values...)
+	}
+	return URLFor(endpoint, values...)
+}
+
+// ServeJSON sends a json response with encoding charset.
+func (c *Controller) ServeJSON(encoding ...bool) {
+	var (
+		hasIndent   = true
+		hasEncoding = false
+	)
+	if BConfig.RunMode == PROD {
+		hasIndent = false
+	}
+	if len(encoding) > 0 && encoding[0] == true {
+		hasEncoding = true
+	}
+	c.Ctx.Output.JSON(c.Data["json"], hasIndent, hasEncoding)
+}
+
+// ServeJSONP sends a jsonp response.
+func (c *Controller) ServeJSONP() {
+	hasIndent := true
+	if BConfig.RunMode == PROD {
+		hasIndent = false
+	}
+	c.Ctx.Output.JSONP(c.Data["jsonp"], hasIndent)
+}
+
+// ServeXML sends xml response.
+func (c *Controller) ServeXML() {
+	hasIndent := true
+	if BConfig.RunMode == PROD {
+		hasIndent = false
+	}
+	c.Ctx.Output.XML(c.Data["xml"], hasIndent)
+}
+
+// ServeFormatted serve Xml OR Json, depending on the value of the Accept header
+func (c *Controller) ServeFormatted() {
+	accept := c.Ctx.Input.Header("Accept")
+	switch accept {
+	case applicationJSON:
+		c.ServeJSON()
+	case applicationXML, textXML:
+		c.ServeXML()
+	default:
+		c.ServeJSON()
+	}
+}
+
+// Input returns the input data map from POST or PUT request body and query string.
+func (c *Controller) Input() url.Values {
+	if c.Ctx.Request.Form == nil {
+		c.Ctx.Request.ParseForm()
+	}
+	return c.Ctx.Request.Form
+}
+
+// ParseForm maps input data map to obj struct.
+func (c *Controller) ParseForm(obj interface{}) error {
+	return ParseForm(c.Input(), obj)
+}
+
+// GetString returns the input value by key string or the default value while it's present and input is blank
+func (c *Controller) GetString(key string, def ...string) string {
+	if v := c.Ctx.Input.Query(key); v != "" {
+		return v
+	}
+	if len(def) > 0 {
+		return def[0]
+	}
+	return ""
+}
+
+// GetStrings returns the input string slice by key string or the default value while it's present and input is blank
+// it's designed for multi-value input field such as checkbox(input[type=checkbox]), multi-selection.
+func (c *Controller) GetStrings(key string, def ...[]string) []string {
+	var defv []string
+	if len(def) > 0 {
+		defv = def[0]
+	}
+
+	if f := c.Input(); f == nil {
+		return defv
+	} else if vs := f[key]; len(vs) > 0 {
+		return vs
+	}
+
+	return defv
+}
+
+// GetInt returns input as an int or the default value while it's present and input is blank
+func (c *Controller) GetInt(key string, def ...int) (int, error) {
+	strv := c.Ctx.Input.Query(key)
+	if len(strv) == 0 && len(def) > 0 {
+		return def[0], nil
+	}
+	return strconv.Atoi(strv)
+}
+
+// GetInt8 return input as an int8 or the default value while it's present and input is blank
+func (c *Controller) GetInt8(key string, def ...int8) (int8, error) {
+	strv := c.Ctx.Input.Query(key)
+	if len(strv) == 0 && len(def) > 0 {
+		return def[0], nil
+	}
+	i64, err := strconv.ParseInt(strv, 10, 8)
+	return int8(i64), err
+}
+
+// GetUint8 return input as an uint8 or the default value while it's present and input is blank
+func (c *Controller) GetUint8(key string, def ...uint8) (uint8, error) {
+	strv := c.Ctx.Input.Query(key)
+	if len(strv) == 0 && len(def) > 0 {
+		return def[0], nil
+	}
+	u64, err := strconv.ParseUint(strv, 10, 8)
+	return uint8(u64), err
+}
+
+// GetInt16 returns input as an int16 or the default value while it's present and input is blank
+func (c *Controller) GetInt16(key string, def ...int16) (int16, error) {
+	strv := c.Ctx.Input.Query(key)
+	if len(strv) == 0 && len(def) > 0 {
+		return def[0], nil
+	}
+	i64, err := strconv.ParseInt(strv, 10, 16)
+	return int16(i64), err
+}
+
+// GetUint16 returns input as an uint16 or the default value while it's present and input is blank
+func (c *Controller) GetUint16(key string, def ...uint16) (uint16, error) {
+	strv := c.Ctx.Input.Query(key)
+	if len(strv) == 0 && len(def) > 0 {
+		return def[0], nil
+	}
+	u64, err := strconv.ParseUint(strv, 10, 16)
+	return uint16(u64), err
+}
+
+// GetInt32 returns input as an int32 or the default value while it's present and input is blank
+func (c *Controller) GetInt32(key string, def ...int32) (int32, error) {
+	strv := c.Ctx.Input.Query(key)
+	if len(strv) == 0 && len(def) > 0 {
+		return def[0], nil
+	}
+	i64, err := strconv.ParseInt(strv, 10, 32)
+	return int32(i64), err
+}
+
+// GetUint32 returns input as an uint32 or the default value while it's present and input is blank
+func (c *Controller) GetUint32(key string, def ...uint32) (uint32, error) {
+	strv := c.Ctx.Input.Query(key)
+	if len(strv) == 0 && len(def) > 0 {
+		return def[0], nil
+	}
+	u64, err := strconv.ParseUint(strv, 10, 32)
+	return uint32(u64), err
+}
+
+// GetInt64 returns input value as int64 or the default value while it's present and input is blank.
+func (c *Controller) GetInt64(key string, def ...int64) (int64, error) {
+	strv := c.Ctx.Input.Query(key)
+	if len(strv) == 0 && len(def) > 0 {
+		return def[0], nil
+	}
+	return strconv.ParseInt(strv, 10, 64)
+}
+
+// GetUint64 returns input value as uint64 or the default value while it's present and input is blank.
+func (c *Controller) GetUint64(key string, def ...uint64) (uint64, error) {
+	strv := c.Ctx.Input.Query(key)
+	if len(strv) == 0 && len(def) > 0 {
+		return def[0], nil
+	}
+	return strconv.ParseUint(strv, 10, 64)
+}
+
+// GetBool returns input value as bool or the default value while it's present and input is blank.
+func (c *Controller) GetBool(key string, def ...bool) (bool, error) {
+	strv := c.Ctx.Input.Query(key)
+	if len(strv) == 0 && len(def) > 0 {
+		return def[0], nil
+	}
+	return strconv.ParseBool(strv)
+}
+
+// GetFloat returns input value as float64 or the default value while it's present and input is blank.
+func (c *Controller) GetFloat(key string, def ...float64) (float64, error) {
+	strv := c.Ctx.Input.Query(key)
+	if len(strv) == 0 && len(def) > 0 {
+		return def[0], nil
+	}
+	return strconv.ParseFloat(strv, 64)
+}
+
+// GetFile returns the file data in file upload field named as key.
+// it returns the first one of multi-uploaded files.
+func (c *Controller) GetFile(key string) (multipart.File, *multipart.FileHeader, error) {
+	return c.Ctx.Request.FormFile(key)
+}
+
+// GetFiles return multi-upload files
+// files, err:=c.GetFiles("myfiles")
+//	if err != nil {
+//		http.Error(w, err.Error(), http.StatusNoContent)
+//		return
+//	}
+// for i, _ := range files {
+//	//for each fileheader, get a handle to the actual file
+//	file, err := files[i].Open()
+//	defer file.Close()
+//	if err != nil {
+//		http.Error(w, err.Error(), http.StatusInternalServerError)
+//		return
+//	}
+//	//create destination file making sure the path is writeable.
+//	dst, err := os.Create("upload/" + files[i].Filename)
+//	defer dst.Close()
+//	if err != nil {
+//		http.Error(w, err.Error(), http.StatusInternalServerError)
+//		return
+//	}
+//	//copy the uploaded file to the destination file
+//	if _, err := io.Copy(dst, file); err != nil {
+//		http.Error(w, err.Error(), http.StatusInternalServerError)
+//		return
+//	}
+// }
+func (c *Controller) GetFiles(key string) ([]*multipart.FileHeader, error) {
+	if files, ok := c.Ctx.Request.MultipartForm.File[key]; ok {
+		return files, nil
+	}
+	return nil, http.ErrMissingFile
+}
+
+// SaveToFile saves uploaded file to new path.
+// it only operates the first one of mutil-upload form file field.
+func (c *Controller) SaveToFile(fromfile, tofile string) error {
+	file, _, err := c.Ctx.Request.FormFile(fromfile)
+	if err != nil {
+		return err
+	}
+	defer file.Close()
+	f, err := os.OpenFile(tofile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+	io.Copy(f, file)
+	return nil
+}
+
+// StartSession starts session and load old session data info this controller.
+func (c *Controller) StartSession() session.Store {
+	if c.CruSession == nil {
+		c.CruSession = c.Ctx.Input.CruSession
+	}
+	return c.CruSession
+}
+
+// SetSession puts value into session.
+func (c *Controller) SetSession(name interface{}, value interface{}) {
+	if c.CruSession == nil {
+		c.StartSession()
+	}
+	c.CruSession.Set(name, value)
+}
+
+// GetSession gets value from session.
+func (c *Controller) GetSession(name interface{}) interface{} {
+	if c.CruSession == nil {
+		c.StartSession()
+	}
+	return c.CruSession.Get(name)
+}
+
+// DelSession removes value from session.
+func (c *Controller) DelSession(name interface{}) {
+	if c.CruSession == nil {
+		c.StartSession()
+	}
+	c.CruSession.Delete(name)
+}
+
+// SessionRegenerateID regenerates session id for this session.
+// the session data have no changes.
+func (c *Controller) SessionRegenerateID() {
+	if c.CruSession != nil {
+		c.CruSession.SessionRelease(c.Ctx.ResponseWriter)
+	}
+	c.CruSession = GlobalSessions.SessionRegenerateID(c.Ctx.ResponseWriter, c.Ctx.Request)
+	c.Ctx.Input.CruSession = c.CruSession
+}
+
+// DestroySession cleans session data and session cookie.
+func (c *Controller) DestroySession() {
+	c.Ctx.Input.CruSession.Flush()
+	c.Ctx.Input.CruSession = nil
+	GlobalSessions.SessionDestroy(c.Ctx.ResponseWriter, c.Ctx.Request)
+}
+
+// IsAjax returns this request is ajax or not.
+func (c *Controller) IsAjax() bool {
+	return c.Ctx.Input.IsAjax()
+}
+
+// GetSecureCookie returns decoded cookie value from encoded browser cookie values.
+func (c *Controller) GetSecureCookie(Secret, key string) (string, bool) {
+	return c.Ctx.GetSecureCookie(Secret, key)
+}
+
+// SetSecureCookie puts value into cookie after encoded the value.
+func (c *Controller) SetSecureCookie(Secret, name, value string, others ...interface{}) {
+	c.Ctx.SetSecureCookie(Secret, name, value, others...)
+}
+
+// XSRFToken creates a CSRF token string and returns.
+func (c *Controller) XSRFToken() string {
+	if c._xsrfToken == "" {
+		expire := int64(BConfig.WebConfig.XSRFExpire)
+		if c.XSRFExpire > 0 {
+			expire = int64(c.XSRFExpire)
+		}
+		c._xsrfToken = c.Ctx.XSRFToken(BConfig.WebConfig.XSRFKey, expire)
+	}
+	return c._xsrfToken
+}
+
+// CheckXSRFCookie checks xsrf token in this request is valid or not.
+// the token can provided in request header "X-Xsrftoken" and "X-CsrfToken"
+// or in form field value named as "_xsrf".
+func (c *Controller) CheckXSRFCookie() bool {
+	if !c.EnableXSRF {
+		return true
+	}
+	return c.Ctx.CheckXSRFCookie()
+}
+
+// XSRFFormHTML writes an input field contains xsrf token value.
+func (c *Controller) XSRFFormHTML() string {
+	return `<input type="hidden" name="_xsrf" value="` +
+		c.XSRFToken() + `" />`
+}
+
+// GetControllerAndAction gets the executing controller name and action name.
+func (c *Controller) GetControllerAndAction() (string, string) {
+	return c.controllerName, c.actionName
+}

+ 181 - 0
vendor/github.com/fatedier/beego/controller_test.go

@@ -0,0 +1,181 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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 beego
+
+import (
+	"math"
+	"strconv"
+	"testing"
+
+	"github.com/astaxie/beego/context"
+	"os"
+	"path/filepath"
+)
+
+func TestGetInt(t *testing.T) {
+	i := context.NewInput()
+	i.SetParam("age", "40")
+	ctx := &context.Context{Input: i}
+	ctrlr := Controller{Ctx: ctx}
+	val, _ := ctrlr.GetInt("age")
+	if val != 40 {
+		t.Errorf("TestGetInt expect 40,get %T,%v", val, val)
+	}
+}
+
+func TestGetInt8(t *testing.T) {
+	i := context.NewInput()
+	i.SetParam("age", "40")
+	ctx := &context.Context{Input: i}
+	ctrlr := Controller{Ctx: ctx}
+	val, _ := ctrlr.GetInt8("age")
+	if val != 40 {
+		t.Errorf("TestGetInt8 expect 40,get %T,%v", val, val)
+	}
+	//Output: int8
+}
+
+func TestGetInt16(t *testing.T) {
+	i := context.NewInput()
+	i.SetParam("age", "40")
+	ctx := &context.Context{Input: i}
+	ctrlr := Controller{Ctx: ctx}
+	val, _ := ctrlr.GetInt16("age")
+	if val != 40 {
+		t.Errorf("TestGetInt16 expect 40,get %T,%v", val, val)
+	}
+}
+
+func TestGetInt32(t *testing.T) {
+	i := context.NewInput()
+	i.SetParam("age", "40")
+	ctx := &context.Context{Input: i}
+	ctrlr := Controller{Ctx: ctx}
+	val, _ := ctrlr.GetInt32("age")
+	if val != 40 {
+		t.Errorf("TestGetInt32 expect 40,get %T,%v", val, val)
+	}
+}
+
+func TestGetInt64(t *testing.T) {
+	i := context.NewInput()
+	i.SetParam("age", "40")
+	ctx := &context.Context{Input: i}
+	ctrlr := Controller{Ctx: ctx}
+	val, _ := ctrlr.GetInt64("age")
+	if val != 40 {
+		t.Errorf("TestGeetInt64 expect 40,get %T,%v", val, val)
+	}
+}
+
+func TestGetUint8(t *testing.T) {
+	i := context.NewInput()
+	i.SetParam("age", strconv.FormatUint(math.MaxUint8, 10))
+	ctx := &context.Context{Input: i}
+	ctrlr := Controller{Ctx: ctx}
+	val, _ := ctrlr.GetUint8("age")
+	if val != math.MaxUint8 {
+		t.Errorf("TestGetUint8 expect %v,get %T,%v", math.MaxUint8, val, val)
+	}
+}
+
+func TestGetUint16(t *testing.T) {
+	i := context.NewInput()
+	i.SetParam("age", strconv.FormatUint(math.MaxUint16, 10))
+	ctx := &context.Context{Input: i}
+	ctrlr := Controller{Ctx: ctx}
+	val, _ := ctrlr.GetUint16("age")
+	if val != math.MaxUint16 {
+		t.Errorf("TestGetUint16 expect %v,get %T,%v", math.MaxUint16, val, val)
+	}
+}
+
+func TestGetUint32(t *testing.T) {
+	i := context.NewInput()
+	i.SetParam("age", strconv.FormatUint(math.MaxUint32, 10))
+	ctx := &context.Context{Input: i}
+	ctrlr := Controller{Ctx: ctx}
+	val, _ := ctrlr.GetUint32("age")
+	if val != math.MaxUint32 {
+		t.Errorf("TestGetUint32 expect %v,get %T,%v", math.MaxUint32, val, val)
+	}
+}
+
+func TestGetUint64(t *testing.T) {
+	i := context.NewInput()
+	i.SetParam("age", strconv.FormatUint(math.MaxUint64, 10))
+	ctx := &context.Context{Input: i}
+	ctrlr := Controller{Ctx: ctx}
+	val, _ := ctrlr.GetUint64("age")
+	if val != math.MaxUint64 {
+		t.Errorf("TestGetUint64 expect %v,get %T,%v", uint64(math.MaxUint64), val, val)
+	}
+}
+
+func TestAdditionalViewPaths(t *testing.T) {
+	dir1 := "_beeTmp"
+	dir2 := "_beeTmp2"
+	defer os.RemoveAll(dir1)
+	defer os.RemoveAll(dir2)
+
+	dir1file := "file1.tpl"
+	dir2file := "file2.tpl"
+
+	genFile := func(dir string, name string, content string) {
+		os.MkdirAll(filepath.Dir(filepath.Join(dir, name)), 0777)
+		if f, err := os.Create(filepath.Join(dir, name)); err != nil {
+			t.Fatal(err)
+		} else {
+			defer f.Close()
+			f.WriteString(content)
+			f.Close()
+		}
+
+	}
+	genFile(dir1, dir1file, `<div>{{.Content}}</div>`)
+	genFile(dir2, dir2file, `<html>{{.Content}}</html>`)
+
+	AddViewPath(dir1)
+	AddViewPath(dir2)
+
+	ctrl := Controller{
+		TplName:  "file1.tpl",
+		ViewPath: dir1,
+	}
+	ctrl.Data = map[interface{}]interface{}{
+		"Content": "value2",
+	}
+	if result, err := ctrl.RenderString(); err != nil {
+		t.Fatal(err)
+	} else {
+		if result != "<div>value2</div>" {
+			t.Fatalf("TestAdditionalViewPaths expect %s got %s", "<div>value2</div>", result)
+		}
+	}
+
+	func() {
+		ctrl.TplName = "file2.tpl"
+		defer func() {
+			if r := recover(); r == nil {
+				t.Fatal("TestAdditionalViewPaths expected error")
+			}
+		}()
+		ctrl.RenderString();
+	}()
+
+	ctrl.TplName = "file2.tpl"
+	ctrl.ViewPath = dir2
+	ctrl.RenderString();
+}

+ 17 - 0
vendor/github.com/fatedier/beego/doc.go

@@ -0,0 +1,17 @@
+/*
+Package beego provide a MVC framework
+beego: an open-source, high-performance, modular, full-stack web framework
+
+It is used for rapid development of RESTful APIs, web apps and backend services in Go.
+beego is inspired by Tornado, Sinatra and Flask with the added benefit of some Go-specific features such as interfaces and struct embedding.
+
+	package main
+	import "github.com/astaxie/beego"
+
+	func main() {
+	 beego.Run()
+	}
+
+more information: http://beego.me
+*/
+package beego

+ 452 - 0
vendor/github.com/fatedier/beego/error.go

@@ -0,0 +1,452 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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 beego
+
+import (
+	"fmt"
+	"html/template"
+	"net/http"
+	"reflect"
+	"runtime"
+	"strconv"
+	"strings"
+
+	"github.com/astaxie/beego/context"
+	"github.com/astaxie/beego/utils"
+)
+
+const (
+	errorTypeHandler = iota
+	errorTypeController
+)
+
+var tpl = `
+<!DOCTYPE html>
+<html>
+<head>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+    <title>beego application error</title>
+    <style>
+        html, body, body * {padding: 0; margin: 0;}
+        #header {background:#ffd; border-bottom:solid 2px #A31515; padding: 20px 10px;}
+        #header h2{ }
+        #footer {border-top:solid 1px #aaa; padding: 5px 10px; font-size: 12px; color:green;}
+        #content {padding: 5px;}
+        #content .stack b{ font-size: 13px; color: red;}
+        #content .stack pre{padding-left: 10px;}
+        table {}
+        td.t {text-align: right; padding-right: 5px; color: #888;}
+    </style>
+    <script type="text/javascript">
+    </script>
+</head>
+<body>
+    <div id="header">
+        <h2>{{.AppError}}</h2>
+    </div>
+    <div id="content">
+        <table>
+            <tr>
+                <td class="t">Request Method: </td><td>{{.RequestMethod}}</td>
+            </tr>
+            <tr>
+                <td class="t">Request URL: </td><td>{{.RequestURL}}</td>
+            </tr>
+            <tr>
+                <td class="t">RemoteAddr: </td><td>{{.RemoteAddr }}</td>
+            </tr>
+        </table>
+        <div class="stack">
+            <b>Stack</b>
+            <pre>{{.Stack}}</pre>
+        </div>
+    </div>
+    <div id="footer">
+        <p>beego {{ .BeegoVersion }} (beego framework)</p>
+        <p>golang version: {{.GoVersion}}</p>
+    </div>
+</body>
+</html>
+`
+
+// render default application error page with error and stack string.
+func showErr(err interface{}, ctx *context.Context, stack string) {
+	t, _ := template.New("beegoerrortemp").Parse(tpl)
+	data := map[string]string{
+		"AppError":      fmt.Sprintf("%s:%v", BConfig.AppName, err),
+		"RequestMethod": ctx.Input.Method(),
+		"RequestURL":    ctx.Input.URI(),
+		"RemoteAddr":    ctx.Input.IP(),
+		"Stack":         stack,
+		"BeegoVersion":  VERSION,
+		"GoVersion":     runtime.Version(),
+	}
+	if ctx.Output.Status != 0 {
+		ctx.ResponseWriter.WriteHeader(ctx.Output.Status)
+	} else {
+		ctx.ResponseWriter.WriteHeader(500)
+	}
+	t.Execute(ctx.ResponseWriter, data)
+}
+
+var errtpl = `
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+		<title>{{.Title}}</title>
+		<style type="text/css">
+			* {
+				margin:0;
+				padding:0;
+			}
+
+			body {
+				background-color:#EFEFEF;
+				font: .9em "Lucida Sans Unicode", "Lucida Grande", sans-serif;
+			}
+
+			#wrapper{
+				width:600px;
+				margin:40px auto 0;
+				text-align:center;
+				-moz-box-shadow: 5px 5px 10px rgba(0,0,0,0.3);
+				-webkit-box-shadow: 5px 5px 10px rgba(0,0,0,0.3);
+				box-shadow: 5px 5px 10px rgba(0,0,0,0.3);
+			}
+
+			#wrapper h1{
+				color:#FFF;
+				text-align:center;
+				margin-bottom:20px;
+			}
+
+			#wrapper a{
+				display:block;
+				font-size:.9em;
+				padding-top:20px;
+				color:#FFF;
+				text-decoration:none;
+				text-align:center;
+			}
+
+			#container {
+				width:600px;
+				padding-bottom:15px;
+				background-color:#FFFFFF;
+			}
+
+			.navtop{
+				height:40px;
+				background-color:#24B2EB;
+				padding:13px;
+			}
+
+			.content {
+				padding:10px 10px 25px;
+				background: #FFFFFF;
+				margin:;
+				color:#333;
+			}
+
+			a.button{
+				color:white;
+				padding:15px 20px;
+				text-shadow:1px 1px 0 #00A5FF;
+				font-weight:bold;
+				text-align:center;
+				border:1px solid #24B2EB;
+				margin:0px 200px;
+				clear:both;
+				background-color: #24B2EB;
+				border-radius:100px;
+				-moz-border-radius:100px;
+				-webkit-border-radius:100px;
+			}
+
+			a.button:hover{
+				text-decoration:none;
+				background-color: #24B2EB;
+			}
+
+		</style>
+	</head>
+	<body>
+		<div id="wrapper">
+			<div id="container">
+				<div class="navtop">
+					<h1>{{.Title}}</h1>
+				</div>
+				<div id="content">
+					{{.Content}}
+					<a href="/" title="Home" class="button">Go Home</a><br />
+
+					<br>Powered by beego {{.BeegoVersion}}
+				</div>
+			</div>
+		</div>
+	</body>
+</html>
+`
+
+type errorInfo struct {
+	controllerType reflect.Type
+	handler        http.HandlerFunc
+	method         string
+	errorType      int
+}
+
+// ErrorMaps holds map of http handlers for each error string.
+// there is 10 kinds default error(40x and 50x)
+var ErrorMaps = make(map[string]*errorInfo, 10)
+
+// show 401 unauthorized error.
+func unauthorized(rw http.ResponseWriter, r *http.Request) {
+	responseError(rw, r,
+		401,
+		"<br>The page you have requested can't be authorized."+
+			"<br>Perhaps you are here because:"+
+			"<br><br><ul>"+
+			"<br>The credentials you supplied are incorrect"+
+			"<br>There are errors in the website address"+
+			"</ul>",
+	)
+}
+
+// show 402 Payment Required
+func paymentRequired(rw http.ResponseWriter, r *http.Request) {
+	responseError(rw, r,
+		402,
+		"<br>The page you have requested Payment Required."+
+			"<br>Perhaps you are here because:"+
+			"<br><br><ul>"+
+			"<br>The credentials you supplied are incorrect"+
+			"<br>There are errors in the website address"+
+			"</ul>",
+	)
+}
+
+// show 403 forbidden error.
+func forbidden(rw http.ResponseWriter, r *http.Request) {
+	responseError(rw, r,
+		403,
+		"<br>The page you have requested is forbidden."+
+			"<br>Perhaps you are here because:"+
+			"<br><br><ul>"+
+			"<br>Your address may be blocked"+
+			"<br>The site may be disabled"+
+			"<br>You need to log in"+
+			"</ul>",
+	)
+}
+
+// show 404 not found error.
+func notFound(rw http.ResponseWriter, r *http.Request) {
+	responseError(rw, r,
+		404,
+		"<br>The page you have requested has flown the coop."+
+			"<br>Perhaps you are here because:"+
+			"<br><br><ul>"+
+			"<br>The page has moved"+
+			"<br>The page no longer exists"+
+			"<br>You were looking for your puppy and got lost"+
+			"<br>You like 404 pages"+
+			"</ul>",
+	)
+}
+
+// show 405 Method Not Allowed
+func methodNotAllowed(rw http.ResponseWriter, r *http.Request) {
+	responseError(rw, r,
+		405,
+		"<br>The method you have requested Not Allowed."+
+			"<br>Perhaps you are here because:"+
+			"<br><br><ul>"+
+			"<br>The method specified in the Request-Line is not allowed for the resource identified by the Request-URI"+
+			"<br>The response MUST include an Allow header containing a list of valid methods for the requested resource."+
+			"</ul>",
+	)
+}
+
+// show 500 internal server error.
+func internalServerError(rw http.ResponseWriter, r *http.Request) {
+	responseError(rw, r,
+		500,
+		"<br>The page you have requested is down right now."+
+			"<br><br><ul>"+
+			"<br>Please try again later and report the error to the website administrator"+
+			"<br></ul>",
+	)
+}
+
+// show 501 Not Implemented.
+func notImplemented(rw http.ResponseWriter, r *http.Request) {
+	responseError(rw, r,
+		501,
+		"<br>The page you have requested is Not Implemented."+
+			"<br><br><ul>"+
+			"<br>Please try again later and report the error to the website administrator"+
+			"<br></ul>",
+	)
+}
+
+// show 502 Bad Gateway.
+func badGateway(rw http.ResponseWriter, r *http.Request) {
+	responseError(rw, r,
+		502,
+		"<br>The page you have requested is down right now."+
+			"<br><br><ul>"+
+			"<br>The server, while acting as a gateway or proxy, received an invalid response from the upstream server it accessed in attempting to fulfill the request."+
+			"<br>Please try again later and report the error to the website administrator"+
+			"<br></ul>",
+	)
+}
+
+// show 503 service unavailable error.
+func serviceUnavailable(rw http.ResponseWriter, r *http.Request) {
+	responseError(rw, r,
+		503,
+		"<br>The page you have requested is unavailable."+
+			"<br>Perhaps you are here because:"+
+			"<br><br><ul>"+
+			"<br><br>The page is overloaded"+
+			"<br>Please try again later."+
+			"</ul>",
+	)
+}
+
+// show 504 Gateway Timeout.
+func gatewayTimeout(rw http.ResponseWriter, r *http.Request) {
+	responseError(rw, r,
+		504,
+		"<br>The page you have requested is unavailable"+
+			"<br>Perhaps you are here because:"+
+			"<br><br><ul>"+
+			"<br><br>The server, while acting as a gateway or proxy, did not receive a timely response from the upstream server specified by the URI."+
+			"<br>Please try again later."+
+			"</ul>",
+	)
+}
+
+func responseError(rw http.ResponseWriter, r *http.Request, errCode int, errContent string) {
+	t, _ := template.New("beegoerrortemp").Parse(errtpl)
+	data := map[string]interface{}{
+		"Title":        http.StatusText(errCode),
+		"BeegoVersion": VERSION,
+		"Content":      template.HTML(errContent),
+	}
+	t.Execute(rw, data)
+}
+
+// ErrorHandler registers http.HandlerFunc to each http err code string.
+// usage:
+// 	beego.ErrorHandler("404",NotFound)
+//	beego.ErrorHandler("500",InternalServerError)
+func ErrorHandler(code string, h http.HandlerFunc) *App {
+	ErrorMaps[code] = &errorInfo{
+		errorType: errorTypeHandler,
+		handler:   h,
+		method:    code,
+	}
+	return BeeApp
+}
+
+// ErrorController registers ControllerInterface to each http err code string.
+// usage:
+// 	beego.ErrorController(&controllers.ErrorController{})
+func ErrorController(c ControllerInterface) *App {
+	reflectVal := reflect.ValueOf(c)
+	rt := reflectVal.Type()
+	ct := reflect.Indirect(reflectVal).Type()
+	for i := 0; i < rt.NumMethod(); i++ {
+		methodName := rt.Method(i).Name
+		if !utils.InSlice(methodName, exceptMethod) && strings.HasPrefix(methodName, "Error") {
+			errName := strings.TrimPrefix(methodName, "Error")
+			ErrorMaps[errName] = &errorInfo{
+				errorType:      errorTypeController,
+				controllerType: ct,
+				method:         methodName,
+			}
+		}
+	}
+	return BeeApp
+}
+
+// Exception Write HttpStatus with errCode and Exec error handler if exist.
+func Exception(errCode uint64, ctx *context.Context) {
+	exception(strconv.FormatUint(errCode, 10), ctx)
+}
+
+// show error string as simple text message.
+// if error string is empty, show 503 or 500 error as default.
+func exception(errCode string, ctx *context.Context) {
+	atoi := func(code string) int {
+		v, err := strconv.Atoi(code)
+		if err == nil {
+			return v
+		}
+		if ctx.Output.Status == 0 {
+			return 503
+		}
+		return ctx.Output.Status
+	}
+
+	for _, ec := range []string{errCode, "503", "500"} {
+		if h, ok := ErrorMaps[ec]; ok {
+			executeError(h, ctx, atoi(ec))
+			return
+		}
+	}
+	//if 50x error has been removed from errorMap
+	ctx.ResponseWriter.WriteHeader(atoi(errCode))
+	ctx.WriteString(errCode)
+}
+
+func executeError(err *errorInfo, ctx *context.Context, code int) {
+	if err.errorType == errorTypeHandler {
+		ctx.ResponseWriter.WriteHeader(code)
+		err.handler(ctx.ResponseWriter, ctx.Request)
+		return
+	}
+	if err.errorType == errorTypeController {
+		ctx.Output.SetStatus(code)
+		//Invoke the request handler
+		vc := reflect.New(err.controllerType)
+		execController, ok := vc.Interface().(ControllerInterface)
+		if !ok {
+			panic("controller is not ControllerInterface")
+		}
+		//call the controller init function
+		execController.Init(ctx, err.controllerType.Name(), err.method, vc.Interface())
+
+		//call prepare function
+		execController.Prepare()
+
+		execController.URLMapping()
+
+		method := vc.MethodByName(err.method)
+		method.Call([]reflect.Value{})
+
+		//render template
+		if BConfig.WebConfig.AutoRender {
+			if err := execController.Render(); err != nil {
+				panic(err)
+			}
+		}
+
+		// finish all runrouter. release resource
+		execController.Finish()
+	}
+}

+ 88 - 0
vendor/github.com/fatedier/beego/error_test.go

@@ -0,0 +1,88 @@
+// Copyright 2016 beego Author. All Rights Reserved.
+//
+// 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 beego
+
+import (
+	"net/http"
+	"net/http/httptest"
+	"strconv"
+	"strings"
+	"testing"
+)
+
+type errorTestController struct {
+	Controller
+}
+
+const parseCodeError = "parse code error"
+
+func (ec *errorTestController) Get() {
+	errorCode, err := ec.GetInt("code")
+	if err != nil {
+		ec.Abort(parseCodeError)
+	}
+	if errorCode != 0 {
+		ec.CustomAbort(errorCode, ec.GetString("code"))
+	}
+	ec.Abort("404")
+}
+
+func TestErrorCode_01(t *testing.T) {
+	registerDefaultErrorHandler()
+	for k := range ErrorMaps {
+		r, _ := http.NewRequest("GET", "/error?code="+k, nil)
+		w := httptest.NewRecorder()
+
+		handler := NewControllerRegister()
+		handler.Add("/error", &errorTestController{})
+		handler.ServeHTTP(w, r)
+		code, _ := strconv.Atoi(k)
+		if w.Code != code {
+			t.Fail()
+		}
+		if !strings.Contains(string(w.Body.Bytes()), http.StatusText(code)) {
+			t.Fail()
+		}
+	}
+}
+
+func TestErrorCode_02(t *testing.T) {
+	registerDefaultErrorHandler()
+	r, _ := http.NewRequest("GET", "/error?code=0", nil)
+	w := httptest.NewRecorder()
+
+	handler := NewControllerRegister()
+	handler.Add("/error", &errorTestController{})
+	handler.ServeHTTP(w, r)
+	if w.Code != 404 {
+		t.Fail()
+	}
+}
+
+func TestErrorCode_03(t *testing.T) {
+	registerDefaultErrorHandler()
+	r, _ := http.NewRequest("GET", "/error?code=panic", nil)
+	w := httptest.NewRecorder()
+
+	handler := NewControllerRegister()
+	handler.Add("/error", &errorTestController{})
+	handler.ServeHTTP(w, r)
+	if w.Code != 200 {
+		t.Fail()
+	}
+	if string(w.Body.Bytes()) != parseCodeError {
+		t.Fail()
+	}
+}

+ 44 - 0
vendor/github.com/fatedier/beego/filter.go

@@ -0,0 +1,44 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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 beego
+
+import "github.com/astaxie/beego/context"
+
+// FilterFunc defines a filter function which is invoked before the controller handler is executed.
+type FilterFunc func(*context.Context)
+
+// FilterRouter defines a filter operation which is invoked before the controller handler is executed.
+// It can match the URL against a pattern, and execute a filter function
+// when a request with a matching URL arrives.
+type FilterRouter struct {
+	filterFunc     FilterFunc
+	tree           *Tree
+	pattern        string
+	returnOnOutput bool
+	resetParams    bool
+}
+
+// ValidRouter checks if the current request is matched by this filter.
+// If the request is matched, the values of the URL parameters defined
+// by the filter pattern are also returned.
+func (f *FilterRouter) ValidRouter(url string, ctx *context.Context) bool {
+	isOk := f.tree.Match(url, ctx)
+	if isOk != nil {
+		if b, ok := isOk.(bool); ok {
+			return b
+		}
+	}
+	return false
+}

+ 68 - 0
vendor/github.com/fatedier/beego/filter_test.go

@@ -0,0 +1,68 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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 beego
+
+import (
+	"net/http"
+	"net/http/httptest"
+	"testing"
+
+	"github.com/astaxie/beego/context"
+)
+
+var FilterUser = func(ctx *context.Context) {
+	ctx.Output.Body([]byte("i am " + ctx.Input.Param(":last") + ctx.Input.Param(":first")))
+}
+
+func TestFilter(t *testing.T) {
+	r, _ := http.NewRequest("GET", "/person/asta/Xie", nil)
+	w := httptest.NewRecorder()
+	handler := NewControllerRegister()
+	handler.InsertFilter("/person/:last/:first", BeforeRouter, FilterUser)
+	handler.Add("/person/:last/:first", &TestController{})
+	handler.ServeHTTP(w, r)
+	if w.Body.String() != "i am astaXie" {
+		t.Errorf("user define func can't run")
+	}
+}
+
+var FilterAdminUser = func(ctx *context.Context) {
+	ctx.Output.Body([]byte("i am admin"))
+}
+
+// Filter pattern /admin/:all
+// all url like    /admin/    /admin/xie    will all get filter
+
+func TestPatternTwo(t *testing.T) {
+	r, _ := http.NewRequest("GET", "/admin/", nil)
+	w := httptest.NewRecorder()
+	handler := NewControllerRegister()
+	handler.InsertFilter("/admin/?:all", BeforeRouter, FilterAdminUser)
+	handler.ServeHTTP(w, r)
+	if w.Body.String() != "i am admin" {
+		t.Errorf("filter /admin/ can't run")
+	}
+}
+
+func TestPatternThree(t *testing.T) {
+	r, _ := http.NewRequest("GET", "/admin/astaxie", nil)
+	w := httptest.NewRecorder()
+	handler := NewControllerRegister()
+	handler.InsertFilter("/admin/:all", BeforeRouter, FilterAdminUser)
+	handler.ServeHTTP(w, r)
+	if w.Body.String() != "i am admin" {
+		t.Errorf("filter /admin/astaxie can't run")
+	}
+}

+ 110 - 0
vendor/github.com/fatedier/beego/flash.go

@@ -0,0 +1,110 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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 beego
+
+import (
+	"fmt"
+	"net/url"
+	"strings"
+)
+
+// FlashData is a tools to maintain data when using across request.
+type FlashData struct {
+	Data map[string]string
+}
+
+// NewFlash return a new empty FlashData struct.
+func NewFlash() *FlashData {
+	return &FlashData{
+		Data: make(map[string]string),
+	}
+}
+
+// Set message to flash
+func (fd *FlashData) Set(key string, msg string, args ...interface{}) {
+	if len(args) == 0 {
+		fd.Data[key] = msg
+	} else {
+		fd.Data[key] = fmt.Sprintf(msg, args...)
+	}
+}
+
+// Success writes success message to flash.
+func (fd *FlashData) Success(msg string, args ...interface{}) {
+	if len(args) == 0 {
+		fd.Data["success"] = msg
+	} else {
+		fd.Data["success"] = fmt.Sprintf(msg, args...)
+	}
+}
+
+// Notice writes notice message to flash.
+func (fd *FlashData) Notice(msg string, args ...interface{}) {
+	if len(args) == 0 {
+		fd.Data["notice"] = msg
+	} else {
+		fd.Data["notice"] = fmt.Sprintf(msg, args...)
+	}
+}
+
+// Warning writes warning message to flash.
+func (fd *FlashData) Warning(msg string, args ...interface{}) {
+	if len(args) == 0 {
+		fd.Data["warning"] = msg
+	} else {
+		fd.Data["warning"] = fmt.Sprintf(msg, args...)
+	}
+}
+
+// Error writes error message to flash.
+func (fd *FlashData) Error(msg string, args ...interface{}) {
+	if len(args) == 0 {
+		fd.Data["error"] = msg
+	} else {
+		fd.Data["error"] = fmt.Sprintf(msg, args...)
+	}
+}
+
+// Store does the saving operation of flash data.
+// the data are encoded and saved in cookie.
+func (fd *FlashData) Store(c *Controller) {
+	c.Data["flash"] = fd.Data
+	var flashValue string
+	for key, value := range fd.Data {
+		flashValue += "\x00" + key + "\x23" + BConfig.WebConfig.FlashSeparator + "\x23" + value + "\x00"
+	}
+	c.Ctx.SetCookie(BConfig.WebConfig.FlashName, url.QueryEscape(flashValue), 0, "/")
+}
+
+// ReadFromRequest parsed flash data from encoded values in cookie.
+func ReadFromRequest(c *Controller) *FlashData {
+	flash := NewFlash()
+	if cookie, err := c.Ctx.Request.Cookie(BConfig.WebConfig.FlashName); err == nil {
+		v, _ := url.QueryUnescape(cookie.Value)
+		vals := strings.Split(v, "\x00")
+		for _, v := range vals {
+			if len(v) > 0 {
+				kv := strings.Split(v, "\x23"+BConfig.WebConfig.FlashSeparator+"\x23")
+				if len(kv) == 2 {
+					flash.Data[kv[0]] = kv[1]
+				}
+			}
+		}
+		//read one time then delete it
+		c.Ctx.SetCookie(BConfig.WebConfig.FlashName, "", -1, "/")
+	}
+	c.Data["flash"] = flash.Data
+	return flash
+}

+ 54 - 0
vendor/github.com/fatedier/beego/flash_test.go

@@ -0,0 +1,54 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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 beego
+
+import (
+	"net/http"
+	"net/http/httptest"
+	"strings"
+	"testing"
+)
+
+type TestFlashController struct {
+	Controller
+}
+
+func (t *TestFlashController) TestWriteFlash() {
+	flash := NewFlash()
+	flash.Notice("TestFlashString")
+	flash.Store(&t.Controller)
+	// we choose to serve json because we don't want to load a template html file
+	t.ServeJSON(true)
+}
+
+func TestFlashHeader(t *testing.T) {
+	// create fake GET request
+	r, _ := http.NewRequest("GET", "/", nil)
+	w := httptest.NewRecorder()
+
+	// setup the handler
+	handler := NewControllerRegister()
+	handler.Add("/", &TestFlashController{}, "get:TestWriteFlash")
+	handler.ServeHTTP(w, r)
+
+	// get the Set-Cookie value
+	sc := w.Header().Get("Set-Cookie")
+	// match for the expected header
+	res := strings.Contains(sc, "BEEGO_FLASH=%00notice%23BEEGOFLASH%23TestFlashString%00")
+	// validate the assertion
+	if res != true {
+		t.Errorf("TestFlashHeader() unable to validate flash message")
+	}
+}

+ 28 - 0
vendor/github.com/fatedier/beego/grace/conn.go

@@ -0,0 +1,28 @@
+package grace
+
+import (
+	"errors"
+	"net"
+)
+
+type graceConn struct {
+	net.Conn
+	server *Server
+}
+
+func (c graceConn) Close() (err error) {
+	defer func() {
+		if r := recover(); r != nil {
+			switch x := r.(type) {
+			case string:
+				err = errors.New(x)
+			case error:
+				err = x
+			default:
+				err = errors.New("Unknown panic")
+			}
+		}
+	}()
+	c.server.wg.Done()
+	return c.Conn.Close()
+}

+ 166 - 0
vendor/github.com/fatedier/beego/grace/grace.go

@@ -0,0 +1,166 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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 grace use to hot reload
+// Description: http://grisha.org/blog/2014/06/03/graceful-restart-in-golang/
+//
+// Usage:
+//
+// import(
+//   "log"
+//	 "net/http"
+//	 "os"
+//
+//   "github.com/astaxie/beego/grace"
+// )
+//
+//  func handler(w http.ResponseWriter, r *http.Request) {
+//	  w.Write([]byte("WORLD!"))
+//  }
+//
+//  func main() {
+//      mux := http.NewServeMux()
+//      mux.HandleFunc("/hello", handler)
+//
+//	    err := grace.ListenAndServe("localhost:8080", mux)
+//      if err != nil {
+//		   log.Println(err)
+//	    }
+//      log.Println("Server on 8080 stopped")
+//	     os.Exit(0)
+//    }
+package grace
+
+import (
+	"flag"
+	"net/http"
+	"os"
+	"strings"
+	"sync"
+	"syscall"
+	"time"
+)
+
+const (
+	// PreSignal is the position to add filter before signal
+	PreSignal = iota
+	// PostSignal is the position to add filter after signal
+	PostSignal
+	// StateInit represent the application inited
+	StateInit
+	// StateRunning represent the application is running
+	StateRunning
+	// StateShuttingDown represent the application is shutting down
+	StateShuttingDown
+	// StateTerminate represent the application is killed
+	StateTerminate
+)
+
+var (
+	regLock              *sync.Mutex
+	runningServers       map[string]*Server
+	runningServersOrder  []string
+	socketPtrOffsetMap   map[string]uint
+	runningServersForked bool
+
+	// DefaultReadTimeOut is the HTTP read timeout
+	DefaultReadTimeOut time.Duration
+	// DefaultWriteTimeOut is the HTTP Write timeout
+	DefaultWriteTimeOut time.Duration
+	// DefaultMaxHeaderBytes is the Max HTTP Herder size, default is 0, no limit
+	DefaultMaxHeaderBytes int
+	// DefaultTimeout is the shutdown server's timeout. default is 60s
+	DefaultTimeout = 60 * time.Second
+
+	isChild     bool
+	socketOrder string
+
+	hookableSignals []os.Signal
+)
+
+func init() {
+	flag.BoolVar(&isChild, "graceful", false, "listen on open fd (after forking)")
+	flag.StringVar(&socketOrder, "socketorder", "", "previous initialization order - used when more than one listener was started")
+
+	regLock = &sync.Mutex{}
+	runningServers = make(map[string]*Server)
+	runningServersOrder = []string{}
+	socketPtrOffsetMap = make(map[string]uint)
+
+	hookableSignals = []os.Signal{
+		syscall.SIGHUP,
+		syscall.SIGINT,
+		syscall.SIGTERM,
+	}
+}
+
+// NewServer returns a new graceServer.
+func NewServer(addr string, handler http.Handler) (srv *Server) {
+	regLock.Lock()
+	defer regLock.Unlock()
+
+	if !flag.Parsed() {
+		flag.Parse()
+	}
+	if len(socketOrder) > 0 {
+		for i, addr := range strings.Split(socketOrder, ",") {
+			socketPtrOffsetMap[addr] = uint(i)
+		}
+	} else {
+		socketPtrOffsetMap[addr] = uint(len(runningServersOrder))
+	}
+
+	srv = &Server{
+		wg:      sync.WaitGroup{},
+		sigChan: make(chan os.Signal),
+		isChild: isChild,
+		SignalHooks: map[int]map[os.Signal][]func(){
+			PreSignal: {
+				syscall.SIGHUP:  {},
+				syscall.SIGINT:  {},
+				syscall.SIGTERM: {},
+			},
+			PostSignal: {
+				syscall.SIGHUP:  {},
+				syscall.SIGINT:  {},
+				syscall.SIGTERM: {},
+			},
+		},
+		state:   StateInit,
+		Network: "tcp",
+	}
+	srv.Server = &http.Server{}
+	srv.Server.Addr = addr
+	srv.Server.ReadTimeout = DefaultReadTimeOut
+	srv.Server.WriteTimeout = DefaultWriteTimeOut
+	srv.Server.MaxHeaderBytes = DefaultMaxHeaderBytes
+	srv.Server.Handler = handler
+
+	runningServersOrder = append(runningServersOrder, addr)
+	runningServers[addr] = srv
+
+	return
+}
+
+// ListenAndServe refer http.ListenAndServe
+func ListenAndServe(addr string, handler http.Handler) error {
+	server := NewServer(addr, handler)
+	return server.ListenAndServe()
+}
+
+// ListenAndServeTLS refer http.ListenAndServeTLS
+func ListenAndServeTLS(addr string, certFile string, keyFile string, handler http.Handler) error {
+	server := NewServer(addr, handler)
+	return server.ListenAndServeTLS(certFile, keyFile)
+}

+ 62 - 0
vendor/github.com/fatedier/beego/grace/listener.go

@@ -0,0 +1,62 @@
+package grace
+
+import (
+	"net"
+	"os"
+	"syscall"
+	"time"
+)
+
+type graceListener struct {
+	net.Listener
+	stop    chan error
+	stopped bool
+	server  *Server
+}
+
+func newGraceListener(l net.Listener, srv *Server) (el *graceListener) {
+	el = &graceListener{
+		Listener: l,
+		stop:     make(chan error),
+		server:   srv,
+	}
+	go func() {
+		_ = <-el.stop
+		el.stopped = true
+		el.stop <- el.Listener.Close()
+	}()
+	return
+}
+
+func (gl *graceListener) Accept() (c net.Conn, err error) {
+	tc, err := gl.Listener.(*net.TCPListener).AcceptTCP()
+	if err != nil {
+		return
+	}
+
+	tc.SetKeepAlive(true)
+	tc.SetKeepAlivePeriod(3 * time.Minute)
+
+	c = graceConn{
+		Conn:   tc,
+		server: gl.server,
+	}
+
+	gl.server.wg.Add(1)
+	return
+}
+
+func (gl *graceListener) Close() error {
+	if gl.stopped {
+		return syscall.EINVAL
+	}
+	gl.stop <- nil
+	return <-gl.stop
+}
+
+func (gl *graceListener) File() *os.File {
+	// returns a dup(2) - FD_CLOEXEC flag *not* set
+	tl := gl.Listener.(*net.TCPListener)
+	fl, _ := tl.File()
+	return fl
+}

+ 306 - 0
vendor/github.com/fatedier/beego/grace/server.go

@@ -0,0 +1,306 @@
+package grace
+
+import (
+	"crypto/tls"
+	"fmt"
+	"log"
+	"net"
+	"net/http"
+	"os"
+	"os/exec"
+	"os/signal"
+	"strings"
+	"sync"
+	"syscall"
+	"time"
+)
+
+// Server embedded http.Server
+type Server struct {
+	*http.Server
+	GraceListener    net.Listener
+	SignalHooks      map[int]map[os.Signal][]func()
+	tlsInnerListener *graceListener
+	wg               sync.WaitGroup
+	sigChan          chan os.Signal
+	isChild          bool
+	state            uint8
+	Network          string
+}
+
+// Serve accepts incoming connections on the Listener l,
+// creating a new service goroutine for each.
+// The service goroutines read requests and then call srv.Handler to reply to them.
+func (srv *Server) Serve() (err error) {
+	srv.state = StateRunning
+	err = srv.Server.Serve(srv.GraceListener)
+	log.Println(syscall.Getpid(), "Waiting for connections to finish...")
+	srv.wg.Wait()
+	srv.state = StateTerminate
+	return
+}
+
+// ListenAndServe listens on the TCP network address srv.Addr and then calls Serve
+// to handle requests on incoming connections. If srv.Addr is blank, ":http" is
+// used.
+func (srv *Server) ListenAndServe() (err error) {
+	addr := srv.Addr
+	if addr == "" {
+		addr = ":http"
+	}
+
+	go srv.handleSignals()
+
+	l, err := srv.getListener(addr)
+	if err != nil {
+		log.Println(err)
+		return err
+	}
+
+	srv.GraceListener = newGraceListener(l, srv)
+
+	if srv.isChild {
+		process, err := os.FindProcess(os.Getppid())
+		if err != nil {
+			log.Println(err)
+			return err
+		}
+		err = process.Kill()
+		if err != nil {
+			return err
+		}
+	}
+
+	log.Println(os.Getpid(), srv.Addr)
+	return srv.Serve()
+}
+
+// ListenAndServeTLS listens on the TCP network address srv.Addr and then calls
+// Serve to handle requests on incoming TLS connections.
+//
+// Filenames containing a certificate and matching private key for the server must
+// be provided. If the certificate is signed by a certificate authority, the
+// certFile should be the concatenation of the server's certificate followed by the
+// CA's certificate.
+//
+// If srv.Addr is blank, ":https" is used.
+func (srv *Server) ListenAndServeTLS(certFile, keyFile string) (err error) {
+	addr := srv.Addr
+	if addr == "" {
+		addr = ":https"
+	}
+
+	if srv.TLSConfig == nil {
+		srv.TLSConfig = &tls.Config{}
+	}
+	if srv.TLSConfig.NextProtos == nil {
+		srv.TLSConfig.NextProtos = []string{"http/1.1"}
+	}
+
+	srv.TLSConfig.Certificates = make([]tls.Certificate, 1)
+	srv.TLSConfig.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
+	if err != nil {
+		return
+	}
+
+	go srv.handleSignals()
+
+	l, err := srv.getListener(addr)
+	if err != nil {
+		log.Println(err)
+		return err
+	}
+
+	srv.tlsInnerListener = newGraceListener(l, srv)
+	srv.GraceListener = tls.NewListener(srv.tlsInnerListener, srv.TLSConfig)
+
+	if srv.isChild {
+		process, err := os.FindProcess(os.Getppid())
+		if err != nil {
+			log.Println(err)
+			return err
+		}
+		err = process.Kill()
+		if err != nil {
+			return err
+		}
+	}
+	log.Println(os.Getpid(), srv.Addr)
+	return srv.Serve()
+}
+
+// getListener either opens a new socket to listen on, or takes the acceptor socket
+// it got passed when restarted.
+func (srv *Server) getListener(laddr string) (l net.Listener, err error) {
+	if srv.isChild {
+		var ptrOffset uint
+		if len(socketPtrOffsetMap) > 0 {
+			ptrOffset = socketPtrOffsetMap[laddr]
+			log.Println("laddr", laddr, "ptr offset", socketPtrOffsetMap[laddr])
+		}
+
+		f := os.NewFile(uintptr(3+ptrOffset), "")
+		l, err = net.FileListener(f)
+		if err != nil {
+			err = fmt.Errorf("net.FileListener error: %v", err)
+			return
+		}
+	} else {
+		l, err = net.Listen(srv.Network, laddr)
+		if err != nil {
+			err = fmt.Errorf("net.Listen error: %v", err)
+			return
+		}
+	}
+	return
+}
+
+// handleSignals listens for os Signals and calls any hooked in function that the
+// user had registered with the signal.
+func (srv *Server) handleSignals() {
+	var sig os.Signal
+
+	signal.Notify(
+		srv.sigChan,
+		hookableSignals...,
+	)
+
+	pid := syscall.Getpid()
+	for {
+		sig = <-srv.sigChan
+		srv.signalHooks(PreSignal, sig)
+		switch sig {
+		case syscall.SIGHUP:
+			log.Println(pid, "Received SIGHUP. forking.")
+			err := srv.fork()
+			if err != nil {
+				log.Println("Fork err:", err)
+			}
+		case syscall.SIGINT:
+			log.Println(pid, "Received SIGINT.")
+			srv.shutdown()
+		case syscall.SIGTERM:
+			log.Println(pid, "Received SIGTERM.")
+			srv.shutdown()
+		default:
+			log.Printf("Received %v: nothing i care about...\n", sig)
+		}
+		srv.signalHooks(PostSignal, sig)
+	}
+}
+
+func (srv *Server) signalHooks(ppFlag int, sig os.Signal) {
+	if _, notSet := srv.SignalHooks[ppFlag][sig]; !notSet {
+		return
+	}
+	for _, f := range srv.SignalHooks[ppFlag][sig] {
+		f()
+	}
+	return
+}
+
+// shutdown closes the listener so that no new connections are accepted. it also
+// starts a goroutine that will serverTimeout (stop all running requests) the server
+// after DefaultTimeout.
+func (srv *Server) shutdown() {
+	if srv.state != StateRunning {
+		return
+	}
+
+	srv.state = StateShuttingDown
+	if DefaultTimeout >= 0 {
+		go srv.serverTimeout(DefaultTimeout)
+	}
+	err := srv.GraceListener.Close()
+	if err != nil {
+		log.Println(syscall.Getpid(), "Listener.Close() error:", err)
+	} else {
+		log.Println(syscall.Getpid(), srv.GraceListener.Addr(), "Listener closed.")
+	}
+}
+
+// serverTimeout forces the server to shutdown in a given timeout - whether it
+// finished outstanding requests or not. if Read/WriteTimeout are not set or the
+// max header size is very big a connection could hang
+func (srv *Server) serverTimeout(d time.Duration) {
+	defer func() {
+		if r := recover(); r != nil {
+			log.Println("WaitGroup at 0", r)
+		}
+	}()
+	if srv.state != StateShuttingDown {
+		return
+	}
+	time.Sleep(d)
+	log.Println("[STOP - Hammer Time] Forcefully shutting down parent")
+	for {
+		if srv.state == StateTerminate {
+			break
+		}
+		srv.wg.Done()
+	}
+}
+
+func (srv *Server) fork() (err error) {
+	regLock.Lock()
+	defer regLock.Unlock()
+	if runningServersForked {
+		return
+	}
+	runningServersForked = true
+
+	var files = make([]*os.File, len(runningServers))
+	var orderArgs = make([]string, len(runningServers))
+	for _, srvPtr := range runningServers {
+		switch srvPtr.GraceListener.(type) {
+		case *graceListener:
+			files[socketPtrOffsetMap[srvPtr.Server.Addr]] = srvPtr.GraceListener.(*graceListener).File()
+		default:
+			files[socketPtrOffsetMap[srvPtr.Server.Addr]] = srvPtr.tlsInnerListener.File()
+		}
+		orderArgs[socketPtrOffsetMap[srvPtr.Server.Addr]] = srvPtr.Server.Addr
+	}
+
+	log.Println(files)
+	path := os.Args[0]
+	var args []string
+	if len(os.Args) > 1 {
+		for _, arg := range os.Args[1:] {
+			if arg == "-graceful" {
+				break
+			}
+			args = append(args, arg)
+		}
+	}
+	args = append(args, "-graceful")
+	if len(runningServers) > 1 {
+		args = append(args, fmt.Sprintf(`-socketorder=%s`, strings.Join(orderArgs, ",")))
+		log.Println(args)
+	}
+	cmd := exec.Command(path, args...)
+	cmd.Stdout = os.Stdout
+	cmd.Stderr = os.Stderr
+	cmd.ExtraFiles = files
+	err = cmd.Start()
+	if err != nil {
+		log.Fatalf("Restart: Failed to launch, error: %v", err)
+	}
+
+	return
+}
+
+// RegisterSignalHook registers a function to be run PreSignal or PostSignal for a given signal.
+func (srv *Server) RegisterSignalHook(ppFlag int, sig os.Signal, f func()) (err error) {
+	if ppFlag != PreSignal && ppFlag != PostSignal {
+		err = fmt.Errorf("Invalid ppFlag argument. Must be either grace.PreSignal or grace.PostSignal.")
+		return
+	}
+	for _, s := range hookableSignals {
+		if s == sig {
+			srv.SignalHooks[ppFlag][sig] = append(srv.SignalHooks[ppFlag][sig], f)
+			return
+		}
+	}
+	err = fmt.Errorf("Signal '%v' is not supported.", sig)
+	return
+}

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