[
  {
    "path": ".gitignore",
    "content": "cachedata/\nhttpcache\nGodeps/_workspace\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License\n\nCopyright (c) 2010-2014 Lachlan Donald http://lachlan.me\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "\n# httpcache\n\n`httpcache` provides an [rfc7234][] compliant golang [http.Handler](http://golang.org/pkg/net/http/#Handler).\n\n[![wercker status](https://app.wercker.com/status/a76986990d27e72ea656bb37bb93f59f/m \"wercker status\")](https://app.wercker.com/project/bykey/a76986990d27e72ea656bb37bb93f59f)\n\n[![GoDoc](https://godoc.org/github.com/lox/httpcache?status.svg)](https://godoc.org/github.com/lox/httpcache)\n\n## Example\n\nThis example is from the included CLI, it runs a caching proxy on http://localhost:8080.\n\n```go\nproxy := &httputil.ReverseProxy{\n    Director: func(r *http.Request) {\n    },\n}\n\nhandler := httpcache.NewHandler(httpcache.NewMemoryCache(), proxy)\nhandler.Shared = true\n\nlog.Printf(\"proxy listening on http://%s\", listen)\nlog.Fatal(http.ListenAndServe(listen, handler))\n```\n\n## Implemented\n\n- All of [rfc7234][], except those listed below\n- Disk and Memory storage\n- Apache-like logging via `httplog` package\n\n## Todo\n\n- Offline operation\n- Size constraints on memory/disk cache and cache eviction \n- Correctly handle mixture of HTTP1.0 clients and 1.1 upstreams\n- More detail in `Via` header\n- Support for weak entities with `If-Match` and `If-None-Match`\n- Invalidation based on `Content-Location` and request method\n- Better handling of duplicate headers and CacheControl values\n\n## Caveats\n\n- Conditional requests are never cached, this includes `Range` requests\n\n## Testing\n\nTests are currently conducted via the test suite and verified via the [CoAdvisor tool](http://coad.measurement-factory.com/).\n\n## Reading List\n\n- http://httpwg.github.io/specs/rfc7234.html\n- https://www.mnot.net/blog/2011/07/11/what_proxies_must_do\n- https://www.mnot.net/blog/2014/06/07/rfc2616_is_dead\n\n[rfc7234]: http://httpwg.github.io/specs/rfc7234.html\n"
  },
  {
    "path": "bench_test.go",
    "content": "package httpcache_test\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/http/httputil\"\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/lox/httpcache\"\n)\n\nfunc BenchmarkCachingFiles(b *testing.B) {\n\tbackend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tw.Header().Add(\"Cache-Control\", \"max-age=100000\")\n\t\tfmt.Fprintf(w, \"cache server payload\")\n\t}))\n\tdefer backend.Close()\n\n\tu, err := url.Parse(backend.URL)\n\tif err != nil {\n\t\tb.Fatal(err)\n\t}\n\n\thandler := httpcache.NewHandler(httpcache.NewMemoryCache(), httputil.NewSingleHostReverseProxy(u))\n\thandler.Shared = true\n\tcacheServer := httptest.NewServer(handler)\n\tdefer cacheServer.Close()\n\n\tfor n := 0; n < b.N; n++ {\n\t\tclient := http.Client{}\n\t\tresp, err := client.Get(fmt.Sprintf(\"%s/llamas/%d\", cacheServer.URL, n))\n\t\tif err != nil {\n\t\t\tb.Fatal(err)\n\t\t}\n\t\tresp.Body.Close()\n\t}\n}\n"
  },
  {
    "path": "cache.go",
    "content": "package httpcache\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"crypto/sha256\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net/http\"\n\t\"net/textproto\"\n\t\"os\"\n\tpathutil \"path\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/rainycape/vfs\"\n)\n\nconst (\n\theaderPrefix = \"header/\"\n\tbodyPrefix   = \"body/\"\n\tformatPrefix = \"v1/\"\n)\n\n// Returned when a resource doesn't exist\nvar ErrNotFoundInCache = errors.New(\"Not found in cache\")\n\ntype Cache interface {\n\tHeader(key string) (Header, error)\n\tStore(res *Resource, keys ...string) error\n\tRetrieve(key string) (*Resource, error)\n\tInvalidate(keys ...string)\n\tFreshen(res *Resource, keys ...string) error\n}\n\n// cache provides a storage mechanism for cached Resources\ntype cache struct {\n\tfs    vfs.VFS\n\tstale map[string]time.Time\n}\n\nvar _ Cache = (*cache)(nil)\n\ntype Header struct {\n\thttp.Header\n\tStatusCode int\n}\n\n// NewCache returns a cache backend off the provided VFS\nfunc NewVFSCache(fs vfs.VFS) Cache {\n\treturn &cache{fs: fs, stale: map[string]time.Time{}}\n}\n\n// NewMemoryCache returns an ephemeral cache in memory\nfunc NewMemoryCache() Cache {\n\treturn NewVFSCache(vfs.Memory())\n}\n\n// NewDiskCache returns a disk-backed cache\nfunc NewDiskCache(dir string) (Cache, error) {\n\tif err := os.MkdirAll(dir, 0777); err != nil {\n\t\treturn nil, err\n\t}\n\tfs, err := vfs.FS(dir)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tchfs, err := vfs.Chroot(\"/\", fs)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn NewVFSCache(chfs), nil\n}\n\nfunc (c *cache) vfsWrite(path string, r io.Reader) error {\n\tif err := vfs.MkdirAll(c.fs, pathutil.Dir(path), 0700); err != nil {\n\t\treturn err\n\t}\n\tf, err := c.fs.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer f.Close()\n\tif _, err := io.Copy(f, r); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\n// Retrieve the Status and Headers for a given key path\nfunc (c *cache) Header(key string) (Header, error) {\n\tpath := headerPrefix + formatPrefix + hashKey(key)\n\tf, err := c.fs.Open(path)\n\tif err != nil {\n\t\tif vfs.IsNotExist(err) {\n\t\t\treturn Header{}, ErrNotFoundInCache\n\t\t}\n\t\treturn Header{}, err\n\t}\n\n\treturn readHeaders(bufio.NewReader(f))\n}\n\n// Store a resource against a number of keys\nfunc (c *cache) Store(res *Resource, keys ...string) error {\n\tvar buf = &bytes.Buffer{}\n\n\tif length, err := strconv.ParseInt(res.Header().Get(\"Content-Length\"), 10, 64); err == nil {\n\t\tif _, err = io.CopyN(buf, res, length); err != nil {\n\t\t\treturn err\n\t\t}\n\t} else if _, err = io.Copy(buf, res); err != nil {\n\t\treturn err\n\t}\n\n\tfor _, key := range keys {\n\t\tdelete(c.stale, key)\n\n\t\tif err := c.storeBody(buf, key); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err := c.storeHeader(res.Status(), res.Header(), key); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (c *cache) storeBody(r io.Reader, key string) error {\n\tif err := c.vfsWrite(bodyPrefix+formatPrefix+hashKey(key), r); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc (c *cache) storeHeader(code int, h http.Header, key string) error {\n\thb := &bytes.Buffer{}\n\thb.Write([]byte(fmt.Sprintf(\"HTTP/1.1 %d %s\\r\\n\", code, http.StatusText(code))))\n\theadersToWriter(h, hb)\n\n\tif err := c.vfsWrite(headerPrefix+formatPrefix+hashKey(key), bytes.NewReader(hb.Bytes())); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\n// Retrieve returns a cached Resource for the given key\nfunc (c *cache) Retrieve(key string) (*Resource, error) {\n\tf, err := c.fs.Open(bodyPrefix + formatPrefix + hashKey(key))\n\tif err != nil {\n\t\tif vfs.IsNotExist(err) {\n\t\t\treturn nil, ErrNotFoundInCache\n\t\t}\n\t\treturn nil, err\n\t}\n\th, err := c.Header(key)\n\tif err != nil {\n\t\tif vfs.IsNotExist(err) {\n\t\t\treturn nil, ErrNotFoundInCache\n\t\t}\n\t\treturn nil, err\n\t}\n\tres := NewResource(h.StatusCode, f, h.Header)\n\tif staleTime, exists := c.stale[key]; exists {\n\t\tif !res.DateAfter(staleTime) {\n\t\t\tlog.Printf(\"stale marker of %s found\", staleTime)\n\t\t\tres.MarkStale()\n\t\t}\n\t}\n\treturn res, nil\n}\n\nfunc (c *cache) Invalidate(keys ...string) {\n\tlog.Printf(\"invalidating %q\", keys)\n\tfor _, key := range keys {\n\t\tc.stale[key] = Clock()\n\t}\n}\n\nfunc (c *cache) Freshen(res *Resource, keys ...string) error {\n\tfor _, key := range keys {\n\t\tif h, err := c.Header(key); err == nil {\n\t\t\tif h.StatusCode == res.Status() && headersEqual(h.Header, res.Header()) {\n\t\t\t\tdebugf(\"freshening key %s\", key)\n\t\t\t\tif err := c.storeHeader(h.StatusCode, res.Header(), key); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tdebugf(\"freshen failed, invalidating %s\", key)\n\t\t\t\tc.Invalidate(key)\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc hashKey(key string) string {\n\th := sha256.New()\n\tio.WriteString(h, key)\n\treturn fmt.Sprintf(\"%x\", h.Sum(nil))\n}\n\nfunc readHeaders(r *bufio.Reader) (Header, error) {\n\ttp := textproto.NewReader(r)\n\tline, err := tp.ReadLine()\n\tif err != nil {\n\t\treturn Header{}, err\n\t}\n\n\tf := strings.SplitN(line, \" \", 3)\n\tif len(f) < 2 {\n\t\treturn Header{}, fmt.Errorf(\"malformed HTTP response: %s\", line)\n\t}\n\tstatusCode, err := strconv.Atoi(f[1])\n\tif err != nil {\n\t\treturn Header{}, fmt.Errorf(\"malformed HTTP status code: %s\", f[1])\n\t}\n\n\tmimeHeader, err := tp.ReadMIMEHeader()\n\tif err != nil {\n\t\treturn Header{}, err\n\t}\n\treturn Header{StatusCode: statusCode, Header: http.Header(mimeHeader)}, nil\n}\n\nfunc headersToWriter(h http.Header, w io.Writer) error {\n\tif err := h.Write(w); err != nil {\n\t\treturn err\n\t}\n\t// ReadMIMEHeader expects a trailing newline\n\t_, err := w.Write([]byte(\"\\r\\n\"))\n\treturn err\n}\n"
  },
  {
    "path": "cache_test.go",
    "content": "package httpcache_test\n\nimport (\n\t\"net/http\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/lox/httpcache\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestSaveResource(t *testing.T) {\n\tvar body = strings.Repeat(\"llamas\", 5000)\n\tvar cache = httpcache.NewMemoryCache()\n\n\tres := httpcache.NewResourceBytes(http.StatusOK, []byte(body), http.Header{\n\t\t\"Llamas\": []string{\"true\"},\n\t})\n\n\tif err := cache.Store(res, \"testkey\"); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tresOut, err := cache.Retrieve(\"testkey\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\trequire.NotNil(t, resOut)\n\trequire.Equal(t, res.Header(), resOut.Header())\n\trequire.Equal(t, body, readAllString(resOut))\n}\n\nfunc TestSaveResourceWithIncorrectContentLength(t *testing.T) {\n\tvar body = \"llamas\"\n\tvar cache = httpcache.NewMemoryCache()\n\n\tres := httpcache.NewResourceBytes(http.StatusOK, []byte(body), http.Header{\n\t\t\"Llamas\":         []string{\"true\"},\n\t\t\"Content-Length\": []string{\"10\"},\n\t})\n\n\tif err := cache.Store(res, \"testkey\"); err == nil {\n\t\tt.Fatal(\"Entry should have generated an error\")\n\t}\n\n\t_, err := cache.Retrieve(\"testkey\")\n\tif err != httpcache.ErrNotFoundInCache {\n\t\tt.Fatal(\"Entry shouldn't have been cached\")\n\t}\n}\n"
  },
  {
    "path": "cachecontrol.go",
    "content": "package httpcache\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"sort\"\n\t\"strings\"\n\t\"time\"\n)\n\nconst (\n\tCacheControlHeader = \"Cache-Control\"\n)\n\ntype CacheControl map[string][]string\n\nfunc ParseCacheControlHeaders(h http.Header) (CacheControl, error) {\n\treturn ParseCacheControl(strings.Join(h[\"Cache-Control\"], \", \"))\n}\n\nfunc ParseCacheControl(input string) (CacheControl, error) {\n\tcc := make(CacheControl)\n\tlength := len(input)\n\tisValue := false\n\tlastKey := \"\"\n\n\tfor pos := 0; pos < length; pos++ {\n\t\tvar token string\n\t\tswitch input[pos] {\n\t\tcase '\"':\n\t\t\tif offset := strings.IndexAny(input[pos+1:], `\"`); offset != -1 {\n\t\t\t\ttoken = input[pos+1 : pos+1+offset]\n\t\t\t} else {\n\t\t\t\ttoken = input[pos+1:]\n\t\t\t}\n\t\t\tpos += len(token) + 1\n\t\tcase ',', '\\n', '\\r', ' ', '\\t':\n\t\t\tcontinue\n\t\tcase '=':\n\t\t\tisValue = true\n\t\t\tcontinue\n\t\tdefault:\n\t\t\tif offset := strings.IndexAny(input[pos:], \"\\\"\\n\\t\\r ,=\"); offset != -1 {\n\t\t\t\ttoken = input[pos : pos+offset]\n\t\t\t} else {\n\t\t\t\ttoken = input[pos:]\n\t\t\t}\n\t\t\tpos += len(token) - 1\n\t\t}\n\t\tif isValue {\n\t\t\tcc.Add(lastKey, token)\n\t\t\tisValue = false\n\t\t} else {\n\t\t\tcc.Add(token, \"\")\n\t\t\tlastKey = token\n\t\t}\n\t}\n\n\treturn cc, nil\n}\n\nfunc (cc CacheControl) Get(key string) (string, bool) {\n\tv, exists := cc[key]\n\tif exists && len(v) > 0 {\n\t\treturn v[0], true\n\t}\n\treturn \"\", exists\n}\n\nfunc (cc CacheControl) Add(key, val string) {\n\tif !cc.Has(key) {\n\t\tcc[key] = []string{}\n\t}\n\tif val != \"\" {\n\t\tcc[key] = append(cc[key], val)\n\t}\n}\n\nfunc (cc CacheControl) Has(key string) bool {\n\t_, exists := cc[key]\n\treturn exists\n}\n\nfunc (cc CacheControl) Duration(key string) (time.Duration, error) {\n\td, _ := cc.Get(key)\n\treturn time.ParseDuration(d + \"s\")\n}\n\nfunc (cc CacheControl) String() string {\n\tkeys := make([]string, len(cc))\n\tfor k, _ := range cc {\n\t\tkeys = append(keys, k)\n\t}\n\tsort.Strings(keys)\n\tbuf := bytes.Buffer{}\n\n\tfor _, k := range keys {\n\t\tvals := cc[k]\n\t\tif len(vals) == 0 {\n\t\t\tbuf.WriteString(k + \", \")\n\t\t}\n\t\tfor _, val := range vals {\n\t\t\tbuf.WriteString(fmt.Sprintf(\"%s=%q, \", k, val))\n\t\t}\n\t}\n\n\treturn strings.TrimSuffix(buf.String(), \", \")\n}\n"
  },
  {
    "path": "cachecontrol_test.go",
    "content": "package httpcache_test\n\nimport (\n\t\"testing\"\n\n\t. \"github.com/lox/httpcache\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestParsingCacheControl(t *testing.T) {\n\ttable := []struct {\n\t\tccString string\n\t\tccStruct CacheControl\n\t}{\n\t\t{`public, private=\"set-cookie\", max-age=100`, CacheControl{\n\t\t\t\"public\":  []string{},\n\t\t\t\"private\": []string{\"set-cookie\"},\n\t\t\t\"max-age\": []string{\"100\"},\n\t\t}},\n\t\t{` foo=\"max-age=8, space\",  public`, CacheControl{\n\t\t\t\"public\": []string{},\n\t\t\t\"foo\":    []string{\"max-age=8, space\"},\n\t\t}},\n\t\t{`s-maxage=86400`, CacheControl{\n\t\t\t\"s-maxage\": []string{\"86400\"},\n\t\t}},\n\t\t{`max-stale`, CacheControl{\n\t\t\t\"max-stale\": []string{},\n\t\t}},\n\t\t{`max-stale=60`, CacheControl{\n\t\t\t\"max-stale\": []string{\"60\"},\n\t\t}},\n\t\t{`\" max-age=8,max-age=8 \"=blah`, CacheControl{\n\t\t\t\" max-age=8,max-age=8 \": []string{\"blah\"},\n\t\t}},\n\t}\n\n\tfor _, expect := range table {\n\t\tcc, err := ParseCacheControl(expect.ccString)\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\trequire.Equal(t, cc, expect.ccStruct)\n\t\trequire.NotEmpty(t, cc.String())\n\t}\n}\n\nfunc BenchmarkCacheControlParsing(b *testing.B) {\n\tb.ReportAllocs()\n\tb.ResetTimer()\n\tfor i := 0; i < b.N; i++ {\n\t\t_, err := ParseCacheControl(`public, private=\"set-cookie\", max-age=100`)\n\t\tif err != nil {\n\t\t\tb.Fatal(err)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "cli/httpcache.go",
    "content": "package main\n\nimport (\n\t\"flag\"\n\t\"log\"\n\t\"net/http\"\n\t\"net/http/httputil\"\n\t\"os\"\n\n\t\"github.com/lox/httpcache\"\n\t\"github.com/lox/httpcache/httplog\"\n)\n\nconst (\n\tdefaultListen = \"0.0.0.0:8080\"\n\tdefaultDir    = \"./cachedata\"\n)\n\nvar (\n\tlisten   string\n\tuseDisk  bool\n\tprivate  bool\n\tdir      string\n\tdumpHttp bool\n\tverbose  bool\n)\n\nfunc init() {\n\tflag.StringVar(&listen, \"listen\", defaultListen, \"the host and port to bind to\")\n\tflag.StringVar(&dir, \"dir\", defaultDir, \"the dir to store cache data in, implies -disk\")\n\tflag.BoolVar(&useDisk, \"disk\", false, \"whether to store cache data to disk\")\n\tflag.BoolVar(&verbose, \"v\", false, \"show verbose output and debugging\")\n\tflag.BoolVar(&private, \"private\", false, \"make the cache private\")\n\tflag.BoolVar(&dumpHttp, \"dumphttp\", false, \"dumps http requests and responses to stdout\")\n\tflag.Parse()\n\n\tif verbose {\n\t\thttpcache.DebugLogging = true\n\t}\n}\n\nfunc main() {\n\tproxy := &httputil.ReverseProxy{\n\t\tDirector: func(r *http.Request) {\n\t\t\tr.URL.Scheme = \"http\"\n\t\t\tr.URL.Host = \"127.0.0.1:80\"\n\t\t},\n\t}\n\n\tvar cache httpcache.Cache\n\n\tif useDisk && dir != \"\" {\n\t\tlog.Printf(\"storing cached resources in %s\", dir)\n\t\tif err := os.MkdirAll(dir, 0700); err != nil {\n\t\t\tlog.Fatal(err)\n\t\t}\n\t\tvar err error\n\t\tcache, err = httpcache.NewDiskCache(dir)\n\t\tif err != nil {\n\t\t\tlog.Fatal(err)\n\t\t}\n\t} else {\n\t\tcache = httpcache.NewMemoryCache()\n\t}\n\n\thandler := httpcache.NewHandler(cache, proxy)\n\thandler.Shared = !private\n\n\trespLogger := httplog.NewResponseLogger(handler)\n\trespLogger.DumpRequests = dumpHttp\n\trespLogger.DumpResponses = dumpHttp\n\trespLogger.DumpErrors = dumpHttp\n\n\tlog.Printf(\"listening on http://%s\", listen)\n\tlog.Fatal(http.ListenAndServe(listen, respLogger))\n}\n"
  },
  {
    "path": "handler.go",
    "content": "package httpcache\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"math\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"sync\"\n\t\"time\"\n\n\t\"gopkg.in/djherbis/stream.v1\"\n)\n\nconst (\n\tCacheHeader     = \"X-Cache\"\n\tProxyDateHeader = \"Proxy-Date\"\n)\n\nvar Writes sync.WaitGroup\n\nvar storeable = map[int]bool{\n\thttp.StatusOK:                   true,\n\thttp.StatusFound:                true,\n\thttp.StatusNonAuthoritativeInfo: true,\n\thttp.StatusMultipleChoices:      true,\n\thttp.StatusMovedPermanently:     true,\n\thttp.StatusGone:                 true,\n\thttp.StatusNotFound:             true,\n}\n\nvar cacheableByDefault = map[int]bool{\n\thttp.StatusOK:                   true,\n\thttp.StatusFound:                true,\n\thttp.StatusNotModified:          true,\n\thttp.StatusNonAuthoritativeInfo: true,\n\thttp.StatusMultipleChoices:      true,\n\thttp.StatusMovedPermanently:     true,\n\thttp.StatusGone:                 true,\n\thttp.StatusPartialContent:       true,\n}\n\ntype Handler struct {\n\tShared    bool\n\tupstream  http.Handler\n\tvalidator *Validator\n\tcache     Cache\n}\n\nfunc NewHandler(cache Cache, upstream http.Handler) *Handler {\n\treturn &Handler{\n\t\tupstream:  upstream,\n\t\tcache:     cache,\n\t\tvalidator: &Validator{upstream},\n\t\tShared:    false,\n\t}\n}\n\nfunc (h *Handler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {\n\tcReq, err := newCacheRequest(r)\n\tif err != nil {\n\t\thttp.Error(rw, \"invalid request: \"+err.Error(),\n\t\t\thttp.StatusBadRequest)\n\t\treturn\n\t}\n\n\tif !cReq.isCacheable() {\n\t\tdebugf(\"request not cacheable\")\n\t\trw.Header().Set(CacheHeader, \"SKIP\")\n\t\th.pipeUpstream(rw, cReq)\n\t\treturn\n\t}\n\n\tres, err := h.lookup(cReq)\n\tif err != nil && err != ErrNotFoundInCache {\n\t\thttp.Error(rw, \"lookup error: \"+err.Error(),\n\t\t\thttp.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tcacheType := \"private\"\n\tif h.Shared {\n\t\tcacheType = \"shared\"\n\t}\n\n\tif err == ErrNotFoundInCache {\n\t\tif cReq.CacheControl.Has(\"only-if-cached\") {\n\t\t\thttp.Error(rw, \"key not in cache\",\n\t\t\t\thttp.StatusGatewayTimeout)\n\t\t\treturn\n\t\t}\n\t\tdebugf(\"%s %s not in %s cache\", r.Method, r.URL.String(), cacheType)\n\t\th.passUpstream(rw, cReq)\n\t\treturn\n\t} else {\n\t\tdebugf(\"%s %s found in %s cache\", r.Method, r.URL.String(), cacheType)\n\t}\n\n\tif h.needsValidation(res, cReq) {\n\t\tif cReq.CacheControl.Has(\"only-if-cached\") {\n\t\t\thttp.Error(rw, \"key was in cache, but required validation\",\n\t\t\t\thttp.StatusGatewayTimeout)\n\t\t\treturn\n\t\t}\n\n\t\tdebugf(\"validating cached response\")\n\t\tif h.validator.Validate(r, res) {\n\t\t\tdebugf(\"response is valid\")\n\t\t\th.cache.Freshen(res, cReq.Key.String())\n\t\t} else {\n\t\t\tdebugf(\"response is changed\")\n\t\t\th.passUpstream(rw, cReq)\n\t\t\treturn\n\t\t}\n\t}\n\n\tdebugf(\"serving from cache\")\n\tres.Header().Set(CacheHeader, \"HIT\")\n\th.serveResource(res, rw, cReq)\n\n\tif err := res.Close(); err != nil {\n\t\terrorf(\"Error closing resource: %s\", err.Error())\n\t}\n}\n\n// freshness returns the duration that a requested resource will be fresh for\nfunc (h *Handler) freshness(res *Resource, r *cacheRequest) (time.Duration, error) {\n\tmaxAge, err := res.MaxAge(h.Shared)\n\tif err != nil {\n\t\treturn time.Duration(0), err\n\t}\n\n\tif r.CacheControl.Has(\"max-age\") {\n\t\treqMaxAge, err := r.CacheControl.Duration(\"max-age\")\n\t\tif err != nil {\n\t\t\treturn time.Duration(0), err\n\t\t}\n\n\t\tif reqMaxAge < maxAge {\n\t\t\tdebugf(\"using request max-age of %s\", reqMaxAge.String())\n\t\t\tmaxAge = reqMaxAge\n\t\t}\n\t}\n\n\tage, err := res.Age()\n\tif err != nil {\n\t\treturn time.Duration(0), err\n\t}\n\n\tif res.IsStale() {\n\t\treturn time.Duration(0), nil\n\t}\n\n\tif hFresh := res.HeuristicFreshness(); hFresh > maxAge {\n\t\tdebugf(\"using heuristic freshness of %q\", hFresh)\n\t\tmaxAge = hFresh\n\t}\n\n\treturn maxAge - age, nil\n}\n\nfunc (h *Handler) needsValidation(res *Resource, r *cacheRequest) bool {\n\tif res.MustValidate(h.Shared) {\n\t\treturn true\n\t}\n\n\tfreshness, err := h.freshness(res, r)\n\tif err != nil {\n\t\tdebugf(\"error calculating freshness: %s\", err.Error())\n\t\treturn true\n\t}\n\n\tif r.CacheControl.Has(\"min-fresh\") {\n\t\treqMinFresh, err := r.CacheControl.Duration(\"min-fresh\")\n\t\tif err != nil {\n\t\t\tdebugf(\"error parsing request min-fresh: %s\", err.Error())\n\t\t\treturn true\n\t\t}\n\n\t\tif freshness < reqMinFresh {\n\t\t\tdebugf(\"resource is fresh, but won't satisfy min-fresh of %s\", reqMinFresh)\n\t\t\treturn true\n\t\t}\n\t}\n\n\tdebugf(\"resource has a freshness of %s\", freshness)\n\n\tif freshness <= 0 && r.CacheControl.Has(\"max-stale\") {\n\t\tif len(r.CacheControl[\"max-stale\"]) == 0 {\n\t\t\tdebugf(\"resource is stale, but client sent max-stale\")\n\t\t\treturn false\n\t\t} else if maxStale, _ := r.CacheControl.Duration(\"max-stale\"); maxStale >= (freshness * -1) {\n\t\t\tlog.Printf(\"resource is stale, but within allowed max-stale period of %s\", maxStale)\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn freshness <= 0\n}\n\n// pipeUpstream makes the request via the upstream handler, the response is not stored or modified\nfunc (h *Handler) pipeUpstream(w http.ResponseWriter, r *cacheRequest) {\n\trw := newResponseStreamer(w)\n\trdr, err := rw.Stream.NextReader()\n\tif err != nil {\n\t\tdebugf(\"error creating next stream reader: %v\", err)\n\t\tw.Header().Set(CacheHeader, \"SKIP\")\n\t\th.upstream.ServeHTTP(w, r.Request)\n\t\treturn\n\t}\n\tdefer rdr.Close()\n\n\tdebugf(\"piping request upstream\")\n\tgo func() {\n\t\th.upstream.ServeHTTP(rw, r.Request)\n\t\trw.Stream.Close()\n\t}()\n\trw.WaitHeaders()\n\n\tif r.Method != \"HEAD\" && !r.isStateChanging() {\n\t\treturn\n\t}\n\n\tres := rw.Resource()\n\tdefer res.Close()\n\n\tif r.Method == \"HEAD\" {\n\t\th.cache.Freshen(res, r.Key.ForMethod(\"GET\").String())\n\t} else if res.IsNonErrorStatus() {\n\t\th.invalidateResource(res, r)\n\t}\n}\n\n// passUpstream makes the request via the upstream handler and stores the result\nfunc (h *Handler) passUpstream(w http.ResponseWriter, r *cacheRequest) {\n\trw := newResponseStreamer(w)\n\trdr, err := rw.Stream.NextReader()\n\tif err != nil {\n\t\tdebugf(\"error creating next stream reader: %v\", err)\n\t\tw.Header().Set(CacheHeader, \"SKIP\")\n\t\th.upstream.ServeHTTP(w, r.Request)\n\t\treturn\n\t}\n\n\tt := Clock()\n\tdebugf(\"passing request upstream\")\n\trw.Header().Set(CacheHeader, \"MISS\")\n\n\tgo func() {\n\t\th.upstream.ServeHTTP(rw, r.Request)\n\t\trw.Stream.Close()\n\t}()\n\trw.WaitHeaders()\n\tdebugf(\"upstream responded headers in %s\", Clock().Sub(t).String())\n\n\t// just the headers!\n\tres := NewResourceBytes(rw.StatusCode, nil, rw.Header())\n\tif !h.isCacheable(res, r) {\n\t\trdr.Close()\n\t\tdebugf(\"resource is uncacheable\")\n\t\trw.Header().Set(CacheHeader, \"SKIP\")\n\t\treturn\n\t}\n\tb, err := ioutil.ReadAll(rdr)\n\trdr.Close()\n\tif err != nil {\n\t\tdebugf(\"error reading stream: %v\", err)\n\t\trw.Header().Set(CacheHeader, \"SKIP\")\n\t\treturn\n\t}\n\tdebugf(\"full upstream response took %s\", Clock().Sub(t).String())\n\tres.ReadSeekCloser = &byteReadSeekCloser{bytes.NewReader(b)}\n\n\tif age, err := correctedAge(res.Header(), t, Clock()); err == nil {\n\t\tres.Header().Set(\"Age\", strconv.Itoa(int(math.Ceil(age.Seconds()))))\n\t} else {\n\t\tdebugf(\"error calculating corrected age: %s\", err.Error())\n\t}\n\n\trw.Header().Set(ProxyDateHeader, Clock().Format(http.TimeFormat))\n\th.storeResource(res, r)\n}\n\n// correctedAge adjusts the age of a resource for clock skew and travel time\n// https://httpwg.github.io/specs/rfc7234.html#rfc.section.4.2.3\nfunc correctedAge(h http.Header, reqTime, respTime time.Time) (time.Duration, error) {\n\tdate, err := timeHeader(\"Date\", h)\n\tif err != nil {\n\t\treturn time.Duration(0), err\n\t}\n\n\tapparentAge := respTime.Sub(date)\n\tif apparentAge < 0 {\n\t\tapparentAge = 0\n\t}\n\n\trespDelay := respTime.Sub(reqTime)\n\tageSeconds, err := intHeader(\"Age\", h)\n\tage := time.Second * time.Duration(ageSeconds)\n\tcorrectedAge := age + respDelay\n\n\tif apparentAge > correctedAge {\n\t\tcorrectedAge = apparentAge\n\t}\n\n\tresidentTime := Clock().Sub(respTime)\n\tcurrentAge := correctedAge + residentTime\n\n\treturn currentAge, nil\n}\n\nfunc (h *Handler) isCacheable(res *Resource, r *cacheRequest) bool {\n\tcc, err := res.cacheControl()\n\tif err != nil {\n\t\terrorf(\"Error parsing cache-control: %s\", err.Error())\n\t\treturn false\n\t}\n\n\tif cc.Has(\"no-cache\") || cc.Has(\"no-store\") {\n\t\treturn false\n\t}\n\n\tif cc.Has(\"private\") && len(cc[\"private\"]) == 0 && h.Shared {\n\t\treturn false\n\t}\n\n\tif _, ok := storeable[res.Status()]; !ok {\n\t\treturn false\n\t}\n\n\tif r.Header.Get(\"Authorization\") != \"\" && h.Shared {\n\t\treturn false\n\t}\n\n\tif res.Header().Get(\"Authorization\") != \"\" && h.Shared &&\n\t\t!cc.Has(\"must-revalidate\") && !cc.Has(\"s-maxage\") {\n\t\treturn false\n\t}\n\n\tif res.HasExplicitExpiration() {\n\t\treturn true\n\t}\n\n\tif _, ok := cacheableByDefault[res.Status()]; !ok && !cc.Has(\"public\") {\n\t\treturn false\n\t}\n\n\tif res.HasValidators() {\n\t\treturn true\n\t} else if res.HeuristicFreshness() > 0 {\n\t\treturn true\n\t}\n\n\treturn false\n}\n\nfunc (h *Handler) serveResource(res *Resource, w http.ResponseWriter, req *cacheRequest) {\n\tfor key, headers := range res.Header() {\n\t\tfor _, header := range headers {\n\t\t\tw.Header().Add(key, header)\n\t\t}\n\t}\n\n\tage, err := res.Age()\n\tif err != nil {\n\t\thttp.Error(w, \"Error calculating age: \"+err.Error(),\n\t\t\thttp.StatusInternalServerError)\n\t\treturn\n\t}\n\n\t// http://httpwg.github.io/specs/rfc7234.html#warn.113\n\tif age > (time.Hour*24) && res.HeuristicFreshness() > (time.Hour*24) {\n\t\tw.Header().Add(\"Warning\", `113 - \"Heuristic Expiration\"`)\n\t}\n\n\t// http://httpwg.github.io/specs/rfc7234.html#warn.110\n\tfreshness, err := h.freshness(res, req)\n\tif err != nil || freshness <= 0 {\n\t\tw.Header().Add(\"Warning\", `110 - \"Response is Stale\"`)\n\t}\n\n\tdebugf(\"resource is %s old, updating age from %s\",\n\t\tage.String(), w.Header().Get(\"Age\"))\n\n\tw.Header().Set(\"Age\", fmt.Sprintf(\"%.f\", math.Floor(age.Seconds())))\n\tw.Header().Set(\"Via\", res.Via())\n\n\t// hacky handler for non-ok statuses\n\tif res.Status() != http.StatusOK {\n\t\tw.WriteHeader(res.Status())\n\t\tio.Copy(w, res)\n\t} else {\n\t\thttp.ServeContent(w, req.Request, \"\", res.LastModified(), res)\n\t}\n}\n\nfunc (h *Handler) invalidateResource(res *Resource, r *cacheRequest) {\n\tWrites.Add(1)\n\n\tgo func() {\n\t\tdefer Writes.Done()\n\t\tdebugf(\"invalidating resource %+v\", res)\n\t}()\n}\n\nfunc (h *Handler) storeResource(res *Resource, r *cacheRequest) {\n\tWrites.Add(1)\n\n\tgo func() {\n\t\tdefer Writes.Done()\n\t\tt := Clock()\n\t\tkeys := []string{r.Key.String()}\n\t\theaders := res.Header()\n\n\t\tif h.Shared {\n\t\t\tres.RemovePrivateHeaders()\n\t\t}\n\n\t\t// store a secondary vary version\n\t\tif vary := headers.Get(\"Vary\"); vary != \"\" {\n\t\t\tkeys = append(keys, r.Key.Vary(vary, r.Request).String())\n\t\t}\n\n\t\tif err := h.cache.Store(res, keys...); err != nil {\n\t\t\terrorf(\"storing resources %#v failed with error: %s\", keys, err.Error())\n\t\t}\n\n\t\tdebugf(\"stored resources %+v in %s\", keys, Clock().Sub(t))\n\t}()\n}\n\n// lookupResource finds the best matching Resource for the\n// request, or nil and ErrNotFoundInCache if none is found\nfunc (h *Handler) lookup(req *cacheRequest) (*Resource, error) {\n\tres, err := h.cache.Retrieve(req.Key.String())\n\n\t// HEAD requests can possibly be served from GET\n\tif err == ErrNotFoundInCache && req.Method == \"HEAD\" {\n\t\tres, err = h.cache.Retrieve(req.Key.ForMethod(\"GET\").String())\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif res.HasExplicitExpiration() && req.isCacheable() {\n\t\t\tdebugf(\"using cached GET request for serving HEAD\")\n\t\t\treturn res, nil\n\t\t} else {\n\t\t\treturn nil, ErrNotFoundInCache\n\t\t}\n\t} else if err != nil {\n\t\treturn res, err\n\t}\n\n\t// Secondary lookup for Vary\n\tif vary := res.Header().Get(\"Vary\"); vary != \"\" {\n\t\tres, err = h.cache.Retrieve(req.Key.Vary(vary, req.Request).String())\n\t\tif err != nil {\n\t\t\treturn res, err\n\t\t}\n\t}\n\n\treturn res, nil\n}\n\ntype cacheRequest struct {\n\t*http.Request\n\tKey          Key\n\tTime         time.Time\n\tCacheControl CacheControl\n}\n\nfunc newCacheRequest(r *http.Request) (*cacheRequest, error) {\n\tcc, err := ParseCacheControl(r.Header.Get(\"Cache-Control\"))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif r.Proto == \"HTTP/1.1\" && r.Host == \"\" {\n\t\treturn nil, errors.New(\"Host header can't be empty\")\n\t}\n\n\treturn &cacheRequest{\n\t\tRequest:      r,\n\t\tKey:          NewRequestKey(r),\n\t\tTime:         Clock(),\n\t\tCacheControl: cc,\n\t}, nil\n}\n\nfunc (r *cacheRequest) isStateChanging() bool {\n\tif !(r.Method == \"POST\" || r.Method == \"PUT\" || r.Method == \"DELETE\") {\n\t\treturn true\n\t}\n\n\treturn false\n}\n\nfunc (r *cacheRequest) isCacheable() bool {\n\tif !(r.Method == \"GET\" || r.Method == \"HEAD\") {\n\t\treturn false\n\t}\n\n\tif r.Header.Get(\"If-Match\") != \"\" ||\n\t\tr.Header.Get(\"If-Unmodified-Since\") != \"\" ||\n\t\tr.Header.Get(\"If-Range\") != \"\" {\n\t\treturn false\n\t}\n\n\tif maxAge, ok := r.CacheControl.Get(\"max-age\"); ok && maxAge == \"0\" {\n\t\treturn false\n\t}\n\n\tif r.CacheControl.Has(\"no-store\") || r.CacheControl.Has(\"no-cache\") {\n\t\treturn false\n\t}\n\n\treturn true\n}\n\nfunc newResponseStreamer(w http.ResponseWriter) *responseStreamer {\n\tstrm, err := stream.NewStream(\"responseBuffer\", stream.NewMemFS())\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn &responseStreamer{\n\t\tResponseWriter: w,\n\t\tStream:         strm,\n\t\tC:              make(chan struct{}),\n\t}\n}\n\ntype responseStreamer struct {\n\tStatusCode int\n\thttp.ResponseWriter\n\t*stream.Stream\n\t// C will be closed by WriteHeader to signal the headers' writing.\n\tC chan struct{}\n}\n\n// WaitHeaders returns iff and when WriteHeader has been called.\nfunc (rw *responseStreamer) WaitHeaders() {\n\tfor range rw.C {\n\t}\n}\n\nfunc (rw *responseStreamer) WriteHeader(status int) {\n\tdefer close(rw.C)\n\trw.StatusCode = status\n\trw.ResponseWriter.WriteHeader(status)\n}\n\nfunc (rw *responseStreamer) Write(b []byte) (int, error) {\n\trw.Stream.Write(b)\n\treturn rw.ResponseWriter.Write(b)\n}\nfunc (rw *responseStreamer) Close() error {\n\treturn rw.Stream.Close()\n}\n\n// Resource returns a copy of the responseStreamer as a Resource object\nfunc (rw *responseStreamer) Resource() *Resource {\n\tr, err := rw.Stream.NextReader()\n\tif err == nil {\n\t\tb, err := ioutil.ReadAll(r)\n\t\tr.Close()\n\t\tif err == nil {\n\t\t\treturn NewResourceBytes(rw.StatusCode, b, rw.Header())\n\t\t}\n\t}\n\treturn &Resource{\n\t\theader:         rw.Header(),\n\t\tstatusCode:     rw.StatusCode,\n\t\tReadSeekCloser: errReadSeekCloser{err},\n\t}\n}\n\ntype errReadSeekCloser struct {\n\terr error\n}\n\nfunc (e errReadSeekCloser) Error() string {\n\treturn e.err.Error()\n}\nfunc (e errReadSeekCloser) Close() error                       { return e.err }\nfunc (e errReadSeekCloser) Read(_ []byte) (int, error)         { return 0, e.err }\nfunc (e errReadSeekCloser) Seek(_ int64, _ int) (int64, error) { return 0, e.err }\n"
  },
  {
    "path": "header.go",
    "content": "package httpcache\n\nimport (\n\t\"errors\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"time\"\n)\n\nvar errNoHeader = errors.New(\"Header doesn't exist\")\n\nfunc timeHeader(key string, h http.Header) (time.Time, error) {\n\tif header := h.Get(key); header != \"\" {\n\t\treturn http.ParseTime(header)\n\t} else {\n\t\treturn time.Time{}, errNoHeader\n\t}\n}\n\nfunc intHeader(key string, h http.Header) (int, error) {\n\tif header := h.Get(key); header != \"\" {\n\t\treturn strconv.Atoi(header)\n\t} else {\n\t\treturn 0, errNoHeader\n\t}\n}\n"
  },
  {
    "path": "httplog/log.go",
    "content": "package httplog\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net/http\"\n\t\"net/http/httputil\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n)\n\nconst (\n\tCacheHeader = \"X-Cache\"\n)\n\ntype responseWriter struct {\n\thttp.ResponseWriter\n\tstatus      int\n\tsize        int\n\tt           time.Time\n\terrorOutput bytes.Buffer\n}\n\nfunc (l *responseWriter) Header() http.Header {\n\treturn l.ResponseWriter.Header()\n}\n\nfunc (l *responseWriter) Write(b []byte) (int, error) {\n\tif l.status == 0 {\n\t\tl.status = http.StatusOK\n\t}\n\tif isError(l.status) {\n\t\tl.errorOutput.Write(b)\n\t}\n\tsize, err := l.ResponseWriter.Write(b)\n\tl.size += size\n\treturn size, err\n}\n\nfunc (l *responseWriter) WriteHeader(s int) {\n\tl.ResponseWriter.WriteHeader(s)\n\tl.status = s\n}\n\nfunc (l *responseWriter) Status() int {\n\treturn l.status\n}\n\nfunc (l *responseWriter) Size() int {\n\treturn l.size\n}\n\nfunc NewResponseLogger(delegate http.Handler) *ResponseLogger {\n\treturn &ResponseLogger{Handler: delegate}\n}\n\ntype ResponseLogger struct {\n\thttp.Handler\n\tDumpRequests, DumpErrors, DumpResponses bool\n}\n\nfunc (l *ResponseLogger) ServeHTTP(w http.ResponseWriter, req *http.Request) {\n\tif l.DumpRequests {\n\t\tb, _ := httputil.DumpRequest(req, false)\n\t\twritePrefixString(strings.TrimSpace(string(b)), \">> \", os.Stderr)\n\t}\n\n\trespWr := &responseWriter{ResponseWriter: w, t: time.Now()}\n\tl.Handler.ServeHTTP(respWr, req)\n\n\tif l.DumpResponses {\n\t\tbuf := &bytes.Buffer{}\n\t\tbuf.WriteString(fmt.Sprintf(\"HTTP/1.1 %d %s\\r\\n\",\n\t\t\trespWr.status, http.StatusText(respWr.status),\n\t\t))\n\t\trespWr.Header().Write(buf)\n\t\twritePrefixString(strings.TrimSpace(buf.String()), \"<< \", os.Stderr)\n\t}\n\n\tif l.DumpErrors && isError(respWr.status) {\n\t\twritePrefixString(respWr.errorOutput.String(), \"<< \", os.Stderr)\n\t}\n\n\tl.writeLog(req, respWr)\n}\n\nfunc (l *ResponseLogger) writeLog(req *http.Request, respWr *responseWriter) {\n\tcacheStatus := respWr.Header().Get(CacheHeader)\n\n\tif strings.HasPrefix(cacheStatus, \"HIT\") {\n\t\tcacheStatus = \"\\x1b[32;1mHIT\\x1b[0m\"\n\t} else if strings.HasPrefix(cacheStatus, \"MISS\") {\n\t\tcacheStatus = \"\\x1b[31;1mMISS\\x1b[0m\"\n\t} else {\n\t\tcacheStatus = \"\\x1b[33;1mSKIP\\x1b[0m\"\n\t}\n\n\tclientIP := req.RemoteAddr\n\tif colon := strings.LastIndex(clientIP, \":\"); colon != -1 {\n\t\tclientIP = clientIP[:colon]\n\t}\n\n\tlog.Printf(\n\t\t\"%s \\\"%s %s %s\\\" (%s) %d %s %s\",\n\t\tclientIP,\n\t\treq.Method,\n\t\treq.URL.String(),\n\t\treq.Proto,\n\t\thttp.StatusText(respWr.status),\n\t\trespWr.size,\n\t\tcacheStatus,\n\t\ttime.Now().Sub(respWr.t).String(),\n\t)\n}\n\nfunc isError(code int) bool {\n\treturn code >= 500\n}\n\nfunc writePrefixString(s, prefix string, w io.Writer) {\n\tos.Stderr.Write([]byte(\"\\n\"))\n\tfor _, line := range strings.Split(s, \"\\r\\n\") {\n\t\tw.Write([]byte(prefix))\n\t\tw.Write([]byte(line))\n\t\tw.Write([]byte(\"\\n\"))\n\t}\n\tos.Stderr.Write([]byte(\"\\n\"))\n}\n"
  },
  {
    "path": "key.go",
    "content": "package httpcache\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strings\"\n)\n\n// Key represents a unique identifier for a resource in the cache\ntype Key struct {\n\tmethod string\n\theader http.Header\n\tu      url.URL\n\tvary   []string\n}\n\n// NewKey returns a new Key instance\nfunc NewKey(method string, u *url.URL, h http.Header) Key {\n\treturn Key{method: method, header: h, u: *u, vary: []string{}}\n}\n\n// NewRequestKey generates a Key for a request\nfunc NewRequestKey(r *http.Request) Key {\n\tURL := r.URL\n\n\tif location := r.Header.Get(\"Content-Location\"); location != \"\" {\n\t\tu, err := url.Parse(location)\n\t\tif err == nil {\n\t\t\tif !u.IsAbs() {\n\t\t\t\tu = r.URL.ResolveReference(u)\n\t\t\t}\n\t\t\tif u.Host != r.Host {\n\t\t\t\tdebugf(\"illegal host %q in Content-Location\", u.Host)\n\t\t\t} else {\n\t\t\t\tdebugf(\"using Content-Location: %q\", u.String())\n\t\t\t\tURL = u\n\t\t\t}\n\t\t} else {\n\t\t\tdebugf(\"failed to parse Content-Location %q\", location)\n\t\t}\n\t}\n\n\treturn NewKey(r.Method, URL, r.Header)\n}\n\n// ForMethod returns a new Key with a given method\nfunc (k Key) ForMethod(method string) Key {\n\tk2 := k\n\tk2.method = method\n\treturn k2\n}\n\n// Vary returns a Key that is varied on particular headers in a http.Request\nfunc (k Key) Vary(varyHeader string, r *http.Request) Key {\n\tk2 := k\n\n\tfor _, header := range strings.Split(varyHeader, \", \") {\n\t\tk2.vary = append(k2.vary, header+\"=\"+r.Header.Get(header))\n\t}\n\n\treturn k2\n}\n\nfunc (k Key) String() string {\n\tURL := strings.ToLower(canonicalURL(&k.u).String())\n\tb := &bytes.Buffer{}\n\tb.WriteString(fmt.Sprintf(\"%s:%s\", k.method, URL))\n\n\tif len(k.vary) > 0 {\n\t\tb.WriteString(\"::\")\n\t\tfor _, v := range k.vary {\n\t\t\tb.WriteString(v + \":\")\n\t\t}\n\t}\n\n\treturn b.String()\n}\n\nfunc canonicalURL(u *url.URL) *url.URL {\n\treturn u\n}\n"
  },
  {
    "path": "key_test.go",
    "content": "package httpcache_test\n\nimport (\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/lox/httpcache\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc mustParseUrl(u string) *url.URL {\n\tru, err := url.Parse(u)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn ru\n}\n\nfunc TestKeysDiffer(t *testing.T) {\n\tk1 := httpcache.NewKey(\"GET\", mustParseUrl(\"http://x.org/test\"), nil)\n\tk2 := httpcache.NewKey(\"GET\", mustParseUrl(\"http://y.org/test\"), nil)\n\n\tassert.NotEqual(t, k1.String(), k2.String())\n}\n\nfunc TestRequestKey(t *testing.T) {\n\tr := newRequest(\"GET\", \"http://x.org/test\")\n\n\tk1 := httpcache.NewKey(\"GET\", mustParseUrl(\"http://x.org/test\"), nil)\n\tk2 := httpcache.NewRequestKey(r)\n\n\tassert.Equal(t, k1.String(), k2.String())\n}\n\nfunc TestVaryKey(t *testing.T) {\n\tr := newRequest(\"GET\", \"http://x.org/test\", \"Llamas-1: true\", \"Llamas-2: false\")\n\n\tk1 := httpcache.NewRequestKey(r)\n\tk2 := httpcache.NewRequestKey(r).Vary(\"Llamas-1, Llamas-2\", r)\n\n\tassert.NotEqual(t, k1.String(), k2.String())\n}\n\nfunc TestRequestKeyWithContentLocation(t *testing.T) {\n\tr := newRequest(\"GET\", \"http://x.org/test1\", \"Content-Location: http://x.org/test2\")\n\n\tk1 := httpcache.NewKey(\"GET\", mustParseUrl(\"http://x.org/test2\"), nil)\n\tk2 := httpcache.NewRequestKey(r)\n\n\tassert.Equal(t, k1.String(), k2.String())\n}\n\nfunc TestRequestKeyWithIllegalContentLocation(t *testing.T) {\n\tr := newRequest(\"GET\", \"http://x.org/test1\", \"Content-Location: http://y.org/test2\")\n\n\tk1 := httpcache.NewKey(\"GET\", mustParseUrl(\"http://x.org/test1\"), nil)\n\tk2 := httpcache.NewRequestKey(r)\n\n\tassert.Equal(t, k1.String(), k2.String())\n}\n"
  },
  {
    "path": "logger.go",
    "content": "package httpcache\n\nimport \"log\"\n\nconst (\n\tansiRed   = \"\\x1b[31;1m\"\n\tansiReset = \"\\x1b[0m\"\n)\n\nvar DebugLogging = false\n\nfunc debugf(format string, args ...interface{}) {\n\tif DebugLogging {\n\t\tlog.Printf(format, args...)\n\t}\n}\n\nfunc errorf(format string, args ...interface{}) {\n\tlog.Printf(ansiRed+\"✗ \"+format+ansiReset, args)\n}\n"
  },
  {
    "path": "resource.go",
    "content": "package httpcache\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n\t\"time\"\n)\n\nconst (\n\tlastModDivisor = 10\n\tviaPseudonym   = \"httpcache\"\n)\n\nvar Clock = func() time.Time {\n\treturn time.Now().UTC()\n}\n\ntype ReadSeekCloser interface {\n\tio.Reader\n\tio.Seeker\n\tio.Closer\n}\n\ntype byteReadSeekCloser struct {\n\t*bytes.Reader\n}\n\nfunc (brsc *byteReadSeekCloser) Close() error { return nil }\n\ntype Resource struct {\n\tReadSeekCloser\n\tRequestTime, ResponseTime time.Time\n\theader                    http.Header\n\tstatusCode                int\n\tcc                        CacheControl\n\tstale                     bool\n}\n\nfunc NewResource(statusCode int, body ReadSeekCloser, hdrs http.Header) *Resource {\n\treturn &Resource{\n\t\theader:         hdrs,\n\t\tReadSeekCloser: body,\n\t\tstatusCode:     statusCode,\n\t}\n}\n\nfunc NewResourceBytes(statusCode int, b []byte, hdrs http.Header) *Resource {\n\treturn &Resource{\n\t\theader:         hdrs,\n\t\tstatusCode:     statusCode,\n\t\tReadSeekCloser: &byteReadSeekCloser{bytes.NewReader(b)},\n\t}\n}\n\nfunc (r *Resource) IsNonErrorStatus() bool {\n\treturn r.statusCode >= 200 && r.statusCode < 400\n}\n\nfunc (r *Resource) Status() int {\n\treturn r.statusCode\n}\n\nfunc (r *Resource) Header() http.Header {\n\treturn r.header\n}\n\nfunc (r *Resource) IsStale() bool {\n\treturn r.stale\n}\n\nfunc (r *Resource) MarkStale() {\n\tr.stale = true\n}\n\nfunc (r *Resource) cacheControl() (CacheControl, error) {\n\tif r.cc != nil {\n\t\treturn r.cc, nil\n\t}\n\n\tcc, err := ParseCacheControlHeaders(r.header)\n\tif err != nil {\n\t\treturn cc, err\n\t}\n\n\tr.cc = cc\n\treturn cc, nil\n}\n\nfunc (r *Resource) LastModified() time.Time {\n\tvar modTime time.Time\n\n\tif lastModHeader := r.header.Get(\"Last-Modified\"); lastModHeader != \"\" {\n\t\tif t, err := http.ParseTime(lastModHeader); err == nil {\n\t\t\tmodTime = t\n\t\t}\n\t}\n\n\treturn modTime\n}\n\nfunc (r *Resource) Expires() (time.Time, error) {\n\tif expires := r.header.Get(\"Expires\"); expires != \"\" {\n\t\treturn http.ParseTime(expires)\n\t}\n\n\treturn time.Time{}, nil\n}\n\nfunc (r *Resource) MustValidate(shared bool) bool {\n\tcc, err := r.cacheControl()\n\tif err != nil {\n\t\tdebugf(\"Error parsing Cache-Control: \", err.Error())\n\t\treturn true\n\t}\n\n\t// The s-maxage directive also implies the semantics of proxy-revalidate\n\tif cc.Has(\"s-maxage\") && shared {\n\t\treturn true\n\t}\n\n\tif cc.Has(\"must-revalidate\") || (cc.Has(\"proxy-revalidate\") && shared) {\n\t\treturn true\n\t}\n\n\treturn false\n}\n\nfunc (r *Resource) DateAfter(d time.Time) bool {\n\tif dateHeader := r.header.Get(\"Date\"); dateHeader != \"\" {\n\t\tif t, err := http.ParseTime(dateHeader); err != nil {\n\t\t\treturn false\n\t\t} else {\n\t\t\treturn t.After(d)\n\t\t}\n\t}\n\treturn false\n}\n\n// Calculate the age of the resource\nfunc (r *Resource) Age() (time.Duration, error) {\n\tvar age time.Duration\n\n\tif ageInt, err := intHeader(\"Age\", r.header); err == nil {\n\t\tage = time.Second * time.Duration(ageInt)\n\t}\n\n\tif proxyDate, err := timeHeader(ProxyDateHeader, r.header); err == nil {\n\t\treturn Clock().Sub(proxyDate) + age, nil\n\t}\n\n\tif date, err := timeHeader(\"Date\", r.header); err == nil {\n\t\treturn Clock().Sub(date) + age, nil\n\t}\n\n\treturn time.Duration(0), errors.New(\"Unable to calculate age\")\n}\n\nfunc (r *Resource) MaxAge(shared bool) (time.Duration, error) {\n\tcc, err := r.cacheControl()\n\tif err != nil {\n\t\treturn time.Duration(0), err\n\t}\n\n\tif cc.Has(\"s-maxage\") && shared {\n\t\tif maxAge, err := cc.Duration(\"s-maxage\"); err != nil {\n\t\t\treturn time.Duration(0), err\n\t\t} else if maxAge > 0 {\n\t\t\treturn maxAge, nil\n\t\t}\n\t}\n\n\tif cc.Has(\"max-age\") {\n\t\tif maxAge, err := cc.Duration(\"max-age\"); err != nil {\n\t\t\treturn time.Duration(0), err\n\t\t} else if maxAge > 0 {\n\t\t\treturn maxAge, nil\n\t\t}\n\t}\n\n\tif expiresVal := r.header.Get(\"Expires\"); expiresVal != \"\" {\n\t\texpires, err := http.ParseTime(expiresVal)\n\t\tif err != nil {\n\t\t\treturn time.Duration(0), err\n\t\t}\n\t\treturn expires.Sub(Clock()), nil\n\t}\n\n\treturn time.Duration(0), nil\n}\n\nfunc (r *Resource) RemovePrivateHeaders() {\n\tcc, err := r.cacheControl()\n\tif err != nil {\n\t\tdebugf(\"Error parsing Cache-Control: %s\", err.Error())\n\t}\n\n\tfor _, p := range cc[\"private\"] {\n\t\tdebugf(\"removing private header %q\", p)\n\t\tr.header.Del(p)\n\t}\n}\n\nfunc (r *Resource) HasValidators() bool {\n\tif r.header.Get(\"Last-Modified\") != \"\" || r.header.Get(\"Etag\") != \"\" {\n\t\treturn true\n\t}\n\n\treturn false\n}\n\nfunc (r *Resource) HasExplicitExpiration() bool {\n\tcc, err := r.cacheControl()\n\tif err != nil {\n\t\tdebugf(\"Error parsing Cache-Control: %s\", err.Error())\n\t\treturn false\n\t}\n\n\tif d, _ := cc.Duration(\"max-age\"); d > time.Duration(0) {\n\t\treturn true\n\t}\n\n\tif d, _ := cc.Duration(\"s-maxage\"); d > time.Duration(0) {\n\t\treturn true\n\t}\n\n\tif exp, _ := r.Expires(); !exp.IsZero() {\n\t\treturn true\n\t}\n\n\treturn false\n}\n\nfunc (r *Resource) HeuristicFreshness() time.Duration {\n\tif !r.HasExplicitExpiration() && r.header.Get(\"Last-Modified\") != \"\" {\n\t\treturn Clock().Sub(r.LastModified()) / time.Duration(lastModDivisor)\n\t}\n\n\treturn time.Duration(0)\n}\n\nfunc (r *Resource) Via() string {\n\tvia := []string{}\n\tvia = append(via, fmt.Sprintf(\"1.1 %s\", viaPseudonym))\n\treturn strings.Join(via, \",\")\n}\n"
  },
  {
    "path": "spec_test.go",
    "content": "package httpcache_test\n\nimport (\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"net/http\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/lox/httpcache\"\n\t\"github.com/lox/httpcache/httplog\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc testSetup() (*client, *upstreamServer) {\n\tupstream := &upstreamServer{\n\t\tBody:    []byte(\"llamas\"),\n\t\tasserts: []func(r *http.Request){},\n\t\tNow:     time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC),\n\t\tHeader:  http.Header{},\n\t}\n\n\thttpcache.Clock = func() time.Time {\n\t\treturn upstream.Now\n\t}\n\n\tcacheHandler := httpcache.NewHandler(\n\t\thttpcache.NewMemoryCache(),\n\t\tupstream,\n\t)\n\n\tvar handler http.Handler = cacheHandler\n\n\tif testing.Verbose() {\n\t\trlogger := httplog.NewResponseLogger(cacheHandler)\n\t\trlogger.DumpRequests = true\n\t\trlogger.DumpResponses = true\n\t\thandler = rlogger\n\t\thttpcache.DebugLogging = true\n\t} else {\n\t\tlog.SetOutput(ioutil.Discard)\n\t}\n\n\treturn &client{handler, cacheHandler}, upstream\n}\n\nfunc TestSpecResponseCacheControl(t *testing.T) {\n\tvar cases = []struct {\n\t\tcacheControl   string\n\t\tcacheStatus    string\n\t\trequests       int\n\t\tsecondsElapsed time.Duration\n\t\tshared         bool\n\t}{\n\t\t{cacheControl: \"\", requests: 2},\n\t\t{cacheControl: \"no-cache\", requests: 2, cacheStatus: \"SKIP\"},\n\t\t{cacheControl: \"no-store\", requests: 2, cacheStatus: \"SKIP\"},\n\t\t{cacheControl: \"max-age=0, no-cache\", requests: 2, cacheStatus: \"SKIP\"},\n\t\t{cacheControl: \"max-age=0\", requests: 2, cacheStatus: \"SKIP\"},\n\t\t{cacheControl: \"s-maxage=0\", requests: 2, cacheStatus: \"SKIP\", shared: true},\n\t\t{cacheControl: \"s-maxage=60\", requests: 2, cacheStatus: \"HIT\", shared: true},\n\t\t{cacheControl: \"s-maxage=60\", requests: 2, secondsElapsed: 65, shared: true},\n\t\t{cacheControl: \"max-age=60\", requests: 1, cacheStatus: \"HIT\"},\n\t\t{cacheControl: \"max-age=60\", requests: 1, secondsElapsed: 35, cacheStatus: \"HIT\"},\n\t\t{cacheControl: \"max-age=60\", requests: 2, secondsElapsed: 65},\n\t\t{cacheControl: \"max-age=60, must-revalidate\", requests: 2, cacheStatus: \"HIT\"},\n\t\t{cacheControl: \"max-age=60, proxy-revalidate\", requests: 1, cacheStatus: \"HIT\"},\n\t\t{cacheControl: \"max-age=60, proxy-revalidate\", requests: 2, cacheStatus: \"HIT\", shared: true},\n\t\t{cacheControl: \"private, max-age=60\", requests: 1, cacheStatus: \"HIT\"},\n\t\t{cacheControl: \"private, max-age=60\", requests: 2, cacheStatus: \"SKIP\", shared: true},\n\t}\n\n\tfor idx, c := range cases {\n\t\tclient, upstream := testSetup()\n\t\tupstream.CacheControl = c.cacheControl\n\t\tclient.cacheHandler.Shared = c.shared\n\n\t\tassert.Equal(t, http.StatusOK, client.get(\"/\").Code)\n\t\tupstream.timeTravel(time.Second * time.Duration(c.secondsElapsed))\n\n\t\tr := client.get(\"/\")\n\t\tassert.Equal(t, http.StatusOK, r.statusCode)\n\t\trequire.Equal(t, c.requests, upstream.requests,\n\t\t\tfmt.Sprintf(\"case #%d failed, %+v\", idx+1, c))\n\n\t\tif c.cacheStatus != \"\" {\n\t\t\trequire.Equal(t, c.cacheStatus, r.cacheStatus,\n\t\t\t\tfmt.Sprintf(\"case #%d failed, %+v\", idx+1, c))\n\t\t}\n\t}\n}\n\nfunc TestSpecResponseCacheControlWithPrivateHeaders(t *testing.T) {\n\tclient, upstream := testSetup()\n\tclient.cacheHandler.Shared = false\n\tupstream.CacheControl = `max-age=10, private=X-Llamas, private=Set-Cookie\"`\n\tupstream.Header.Add(\"X-Llamas\", \"fully\")\n\tupstream.Header.Add(\"Set-Cookie\", \"llamas=true\")\n\tassert.Equal(t, http.StatusOK, client.get(\"/r1\").Code)\n\n\tr1 := client.get(\"/r1\")\n\tassert.Equal(t, http.StatusOK, r1.statusCode)\n\tassert.Equal(t, \"HIT\", r1.cacheStatus)\n\tassert.Equal(t, \"fully\", r1.HeaderMap.Get(\"X-Llamas\"))\n\tassert.Equal(t, \"llamas=true\", r1.HeaderMap.Get(\"Set-Cookie\"))\n\tassert.Equal(t, 1, upstream.requests)\n\n\tclient.cacheHandler.Shared = true\n\tassert.Equal(t, http.StatusOK, client.get(\"/r2\").Code)\n\n\tr2 := client.get(\"/r2\")\n\tassert.Equal(t, http.StatusOK, r1.statusCode)\n\tassert.Equal(t, \"HIT\", r2.cacheStatus)\n\tassert.Equal(t, \"\", r2.HeaderMap.Get(\"X-Llamas\"))\n\tassert.Equal(t, \"\", r2.HeaderMap.Get(\"Set-Cookie\"))\n\tassert.Equal(t, 2, upstream.requests)\n}\n\nfunc TestSpecResponseCacheControlWithAuthorizationHeaders(t *testing.T) {\n\tclient, upstream := testSetup()\n\tclient.cacheHandler.Shared = true\n\tupstream.CacheControl = `max-age=10`\n\tupstream.Header.Add(\"Authorization\", \"fully\")\n\tassert.Equal(t, http.StatusOK, client.get(\"/r1\").Code)\n\n\tr1 := client.get(\"/r1\")\n\tassert.Equal(t, http.StatusOK, r1.statusCode)\n\tassert.Equal(t, \"SKIP\", r1.cacheStatus)\n\tassert.Equal(t, \"fully\", r1.HeaderMap.Get(\"Authorization\"))\n\tassert.Equal(t, 2, upstream.requests)\n\n\tclient.cacheHandler.Shared = false\n\tassert.Equal(t, http.StatusOK, client.get(\"/r2\").Code)\n\n\tr3 := client.get(\"/r2\")\n\tassert.Equal(t, http.StatusOK, r3.statusCode)\n\tassert.Equal(t, \"HIT\", r3.cacheStatus)\n\tassert.Equal(t, \"fully\", r3.HeaderMap.Get(\"Authorization\"))\n\tassert.Equal(t, 3, upstream.requests)\n}\n\nfunc TestSpecRequestCacheControl(t *testing.T) {\n\tvar cases = []struct {\n\t\tcacheControl   string\n\t\tcacheStatus    string\n\t\trequests       int\n\t\tsecondsElapsed time.Duration\n\t}{\n\t\t{cacheControl: \"\", requests: 1},\n\t\t{cacheControl: \"no-cache\", requests: 2},\n\t\t{cacheControl: \"no-store\", requests: 2},\n\t\t{cacheControl: \"max-age=0\", requests: 2},\n\t\t{cacheControl: \"max-stale\", requests: 1, secondsElapsed: 65},\n\t\t{cacheControl: \"max-stale=0\", requests: 2, secondsElapsed: 65},\n\t\t{cacheControl: \"max-stale=60\", requests: 1, secondsElapsed: 65},\n\t\t{cacheControl: \"max-stale=60\", requests: 1, secondsElapsed: 65},\n\t\t{cacheControl: \"max-age=30\", requests: 2, secondsElapsed: 40},\n\t\t{cacheControl: \"min-fresh=5\", requests: 1},\n\t\t{cacheControl: \"min-fresh=120\", requests: 2},\n\t}\n\n\tfor idx, c := range cases {\n\t\tclient, upstream := testSetup()\n\t\tupstream.CacheControl = \"max-age=60\"\n\n\t\tassert.Equal(t, http.StatusOK, client.get(\"/\").Code)\n\t\tupstream.timeTravel(time.Second * time.Duration(c.secondsElapsed))\n\n\t\tr := client.get(\"/\", \"Cache-Control: \"+c.cacheControl)\n\t\tassert.Equal(t, http.StatusOK, r.statusCode)\n\t\tassert.Equal(t, c.requests, upstream.requests,\n\t\t\tfmt.Sprintf(\"case #%d failed, %+v\", idx+1, c))\n\t}\n}\n\nfunc TestSpecRequestCacheControlWithOnlyIfCached(t *testing.T) {\n\tclient, upstream := testSetup()\n\tupstream.CacheControl = \"max-age=10\"\n\n\tassert.Equal(t, http.StatusOK, client.get(\"/\").Code)\n\tassert.Equal(t, http.StatusOK, client.get(\"/\").Code)\n\n\tupstream.timeTravel(time.Second * 20)\n\tassert.Equal(t, http.StatusGatewayTimeout,\n\t\tclient.get(\"/\", \"Cache-Control: only-if-cached\").Code)\n\n\tassert.Equal(t, 1, upstream.requests)\n}\n\nfunc TestSpecCachingStatusCodes(t *testing.T) {\n\tclient, upstream := testSetup()\n\tupstream.StatusCode = http.StatusNotFound\n\tupstream.CacheControl = \"public, max-age=60\"\n\n\tr1 := client.get(\"/r1\")\n\tassert.Equal(t, http.StatusNotFound, r1.statusCode)\n\tassert.Equal(t, \"MISS\", r1.cacheStatus)\n\tassert.Equal(t, string(upstream.Body), string(r1.body))\n\n\tupstream.timeTravel(time.Second * 10)\n\tr2 := client.get(\"/r1\")\n\tassert.Equal(t, http.StatusNotFound, r2.statusCode)\n\tassert.Equal(t, \"HIT\", r2.cacheStatus)\n\tassert.Equal(t, string(upstream.Body), string(r2.body))\n\tassert.Equal(t, time.Second*10, r2.age)\n\n\tupstream.StatusCode = http.StatusPaymentRequired\n\tr3 := client.get(\"/r2\")\n\tassert.Equal(t, http.StatusPaymentRequired, r3.statusCode)\n\tassert.Equal(t, \"SKIP\", r3.cacheStatus)\n}\n\nfunc TestSpecConditionalCaching(t *testing.T) {\n\tclient, upstream := testSetup()\n\tupstream.Etag = `\"llamas\"`\n\n\tr1 := client.get(\"/\")\n\tassert.Equal(t, \"MISS\", r1.cacheStatus)\n\tassert.Equal(t, string(upstream.Body), string(r1.body))\n\n\tr2 := client.get(\"/\", `If-None-Match: \"llamas\"`)\n\tassert.Equal(t, http.StatusNotModified, r2.Code)\n\tassert.Equal(t, \"\", string(r2.body))\n\tassert.Equal(t, \"HIT\", r2.cacheStatus)\n}\n\nfunc TestSpecRangeRequests(t *testing.T) {\n\tclient, upstream := testSetup()\n\n\tr1 := client.get(\"/\", \"Range: bytes=0-3\")\n\tassert.Equal(t, http.StatusPartialContent, r1.Code)\n\tassert.Equal(t, \"SKIP\", r1.cacheStatus)\n\tassert.Equal(t, string(upstream.Body[0:4]), string(r1.body))\n}\n\nfunc TestSpecHeuristicCaching(t *testing.T) {\n\tclient, upstream := testSetup()\n\tupstream.LastModified = upstream.Now.AddDate(-1, 0, 0)\n\tassert.Equal(t, \"MISS\", client.get(\"/\").cacheStatus)\n\n\tupstream.timeTravel(time.Hour * 48)\n\tr2 := client.get(\"/\")\n\tassert.Equal(t, \"HIT\", r2.cacheStatus)\n\tassert.Equal(t, []string{\"113 - \\\"Heuristic Expiration\\\"\"}, r2.Header()[\"Warning\"])\n\tassert.Equal(t, 1, upstream.requests, \"The second request shouldn't validate\")\n}\n\nfunc TestSpecCacheControlTrumpsExpires(t *testing.T) {\n\tclient, upstream := testSetup()\n\tupstream.LastModified = upstream.Now.AddDate(-1, 0, 0)\n\tupstream.CacheControl = \"max-age=2\"\n\tassert.Equal(t, \"MISS\", client.get(\"/\").cacheStatus)\n\tassert.Equal(t, \"HIT\", client.get(\"/\").cacheStatus)\n\tassert.Equal(t, 1, upstream.requests)\n\n\tupstream.timeTravel(time.Hour * 48)\n\tassert.Equal(t, \"HIT\", client.get(\"/\").cacheStatus)\n\tassert.Equal(t, 2, upstream.requests)\n}\n\nfunc TestSpecNotCachedWithoutValidatorOrExpiration(t *testing.T) {\n\tclient, upstream := testSetup()\n\tupstream.LastModified = time.Time{}\n\tupstream.Etag = \"\"\n\n\tassert.Equal(t, \"SKIP\", client.get(\"/\").cacheStatus)\n\tassert.Equal(t, \"SKIP\", client.get(\"/\").cacheStatus)\n\tassert.Equal(t, 2, upstream.requests)\n}\n\nfunc TestSpecNoCachingForInvalidExpires(t *testing.T) {\n\tclient, upstream := testSetup()\n\tupstream.LastModified = time.Time{}\n\tupstream.Header.Set(\"Expires\", \"-1\")\n\n\tassert.Equal(t, \"SKIP\", client.get(\"/\").cacheStatus)\n}\n\nfunc TestSpecRequestsWithoutHostHeader(t *testing.T) {\n\tclient, _ := testSetup()\n\n\tr := newRequest(\"GET\", \"http://example.org\")\n\tr.Header.Del(\"Host\")\n\tr.Host = \"\"\n\n\tresp := client.do(r)\n\tassert.Equal(t, http.StatusBadRequest, resp.Code,\n\t\t\"Requests without a Host header should result in a 400\")\n}\n\nfunc TestSpecCacheControlMaxStale(t *testing.T) {\n\tclient, upstream := testSetup()\n\tupstream.CacheControl = \"max-age=60\"\n\tassert.Equal(t, \"MISS\", client.get(\"/\").cacheStatus)\n\n\tupstream.timeTravel(time.Second * 90)\n\tupstream.Body = []byte(\"brand new content\")\n\tr2 := client.get(\"/\", \"Cache-Control: max-stale=3600\")\n\tassert.Equal(t, \"HIT\", r2.cacheStatus)\n\tassert.Equal(t, time.Second*90, r2.age)\n\n\tupstream.timeTravel(time.Second * 90)\n\tr3 := client.get(\"/\")\n\tassert.Equal(t, \"MISS\", r3.cacheStatus)\n\tassert.Equal(t, time.Duration(0), r3.age)\n}\n\nfunc TestSpecValidatingStaleResponsesUnchanged(t *testing.T) {\n\tclient, upstream := testSetup()\n\tupstream.CacheControl = \"max-age=60\"\n\tupstream.Etag = \"llamas1\"\n\tassert.Equal(t, \"MISS\", client.get(\"/\").cacheStatus)\n\n\tupstream.timeTravel(time.Second * 90)\n\tupstream.Header.Add(\"X-New-Header\", \"1\")\n\n\tr2 := client.get(\"/\")\n\tassert.Equal(t, http.StatusOK, r2.Code)\n\tassert.Equal(t, string(upstream.Body), string(r2.body))\n\tassert.Equal(t, \"HIT\", r2.cacheStatus)\n}\n\nfunc TestSpecValidatingStaleResponsesWithNewContent(t *testing.T) {\n\tclient, upstream := testSetup()\n\tupstream.CacheControl = \"max-age=60\"\n\tassert.Equal(t, \"MISS\", client.get(\"/\").cacheStatus)\n\n\tupstream.timeTravel(time.Second * 90)\n\tupstream.Body = []byte(\"brand new content\")\n\n\tr2 := client.get(\"/\")\n\tassert.Equal(t, http.StatusOK, r2.Code)\n\tassert.Equal(t, \"MISS\", r2.cacheStatus)\n\tassert.Equal(t, \"brand new content\", string(r2.body))\n\tassert.Equal(t, time.Duration(0), r2.age)\n}\n\nfunc TestSpecValidatingStaleResponsesWithNewEtag(t *testing.T) {\n\tclient, upstream := testSetup()\n\tupstream.CacheControl = \"max-age=60\"\n\tupstream.Etag = \"llamas1\"\n\n\tassert.Equal(t, \"MISS\", client.get(\"/\").cacheStatus)\n\n\tupstream.timeTravel(time.Second * 90)\n\tupstream.Etag = \"llamas2\"\n\n\tr2 := client.get(\"/\")\n\tassert.Equal(t, http.StatusOK, r2.Code)\n\tassert.Equal(t, \"MISS\", r2.cacheStatus)\n}\n\nfunc TestSpecVaryHeader(t *testing.T) {\n\tclient, upstream := testSetup()\n\tupstream.CacheControl = \"max-age=60\"\n\tupstream.Vary = \"Accept-Language\"\n\tupstream.Etag = \"llamas\"\n\n\tassert.Equal(t, \"MISS\", client.get(\"/\", \"Accept-Language: en\").cacheStatus)\n\tassert.Equal(t, \"HIT\", client.get(\"/\", \"Accept-Language: en\").cacheStatus)\n\tassert.Equal(t, \"MISS\", client.get(\"/\", \"Accept-Language: de\").cacheStatus)\n\tassert.Equal(t, \"HIT\", client.get(\"/\", \"Accept-Language: de\").cacheStatus)\n}\n\nfunc TestSpecHeadersPropagated(t *testing.T) {\n\tclient, upstream := testSetup()\n\tupstream.CacheControl = \"max-age=60\"\n\tupstream.Header.Add(\"X-Llamas\", \"1\")\n\tupstream.Header.Add(\"X-Llamas\", \"3\")\n\tupstream.Header.Add(\"X-Llamas\", \"2\")\n\n\tassert.Equal(t, \"MISS\", client.get(\"/\").cacheStatus)\n\n\tr2 := client.get(\"/\")\n\tassert.Equal(t, \"HIT\", r2.cacheStatus)\n\tassert.Equal(t, []string{\"1\", \"3\", \"2\"}, r2.Header()[\"X-Llamas\"])\n}\n\nfunc TestSpecAgeHeaderFromUpstream(t *testing.T) {\n\tclient, upstream := testSetup()\n\tupstream.CacheControl = \"max-age=86400\"\n\tupstream.Header.Set(\"Age\", \"3600\") //1hr\n\tassert.Equal(t, time.Hour, client.get(\"/\").age)\n\n\tupstream.timeTravel(time.Hour * 2)\n\tassert.Equal(t, time.Hour*3, client.get(\"/\").age)\n}\n\nfunc TestSpecAgeHeaderWithResponseDelay(t *testing.T) {\n\tclient, upstream := testSetup()\n\tupstream.CacheControl = \"max-age=86400\"\n\tupstream.Header.Set(\"Age\", \"3600\") //1hr\n\tupstream.ResponseDuration = time.Second * 2\n\tassert.Equal(t, time.Second*3602, client.get(\"/\").age)\n\n\tupstream.timeTravel(time.Second * 60)\n\tassert.Equal(t, time.Second*3662, client.get(\"/\").age)\n\tassert.Equal(t, 1, upstream.requests)\n}\n\nfunc TestSpecAgeHeaderGeneratedWhereNoneExists(t *testing.T) {\n\tclient, upstream := testSetup()\n\tupstream.CacheControl = \"max-age=86400\"\n\tupstream.ResponseDuration = time.Second * 2\n\tassert.Equal(t, time.Second*2, client.get(\"/\").age)\n\n\tupstream.timeTravel(time.Second * 60)\n\tassert.Equal(t, time.Second*62, client.get(\"/\").age)\n\tassert.Equal(t, 1, upstream.requests)\n}\n\nfunc TestSpecWarningForOldContent(t *testing.T) {\n\tclient, upstream := testSetup()\n\tupstream.LastModified = upstream.Now.AddDate(-1, 0, 0)\n\tassert.Equal(t, \"MISS\", client.get(\"/\").cacheStatus)\n\n\tupstream.timeTravel(time.Hour * 48)\n\tr2 := client.get(\"/\")\n\tassert.Equal(t, \"HIT\", r2.cacheStatus)\n\tassert.Equal(t, []string{\"113 - \\\"Heuristic Expiration\\\"\"}, r2.Header()[\"Warning\"])\n}\n\nfunc TestSpecHeadCanBeServedFromCacheOnlyWithExplicitFreshness(t *testing.T) {\n\tclient, upstream := testSetup()\n\tupstream.CacheControl = \"max-age=3600\"\n\tassert.Equal(t, \"MISS\", client.get(\"/explicit\").cacheStatus)\n\tassert.Equal(t, \"HIT\", client.head(\"/explicit\").cacheStatus)\n\tassert.Equal(t, \"HIT\", client.head(\"/explicit\").cacheStatus)\n\n\tupstream.CacheControl = \"\"\n\tassert.Equal(t, \"SKIP\", client.get(\"/implicit\").cacheStatus)\n\tassert.Equal(t, \"SKIP\", client.head(\"/implicit\").cacheStatus)\n\tassert.Equal(t, \"SKIP\", client.head(\"/implicit\").cacheStatus)\n}\n\nfunc TestSpecInvalidatingGetWithHeadRequest(t *testing.T) {\n\tclient, upstream := testSetup()\n\tupstream.CacheControl = \"max-age=3600\"\n\tassert.Equal(t, \"MISS\", client.get(\"/explicit\").cacheStatus)\n\n\tupstream.Body = []byte(\"brand new content\")\n\tassert.Equal(t, \"SKIP\", client.head(\"/explicit\", \"Cache-Control: max-age=0\").cacheStatus)\n\tassert.Equal(t, \"MISS\", client.get(\"/explicit\").cacheStatus)\n}\n\nfunc TestSpecFresheningGetWithHeadRequest(t *testing.T) {\n\tclient, upstream := testSetup()\n\tupstream.CacheControl = \"max-age=3600\"\n\tassert.Equal(t, \"MISS\", client.get(\"/explicit\").cacheStatus)\n\n\tupstream.timeTravel(time.Second * 10)\n\tassert.Equal(t, 10*time.Second, client.get(\"/explicit\").age)\n\n\tupstream.Header.Add(\"X-Llamas\", \"llamas\")\n\tassert.Equal(t, \"SKIP\", client.head(\"/explicit\", \"Cache-Control: max-age=0\").cacheStatus)\n\n\trefreshed := client.get(\"/explicit\")\n\tassert.Equal(t, \"HIT\", refreshed.cacheStatus)\n\tassert.Equal(t, time.Duration(0), refreshed.age)\n\tassert.Equal(t, \"llamas\", refreshed.header.Get(\"X-Llamas\"))\n}\n\nfunc TestSpecContentHeaderInRequestRespected(t *testing.T) {\n\tclient, upstream := testSetup()\n\tupstream.CacheControl = \"max-age=3600\"\n\n\tr1 := client.get(\"/llamas/rock\")\n\tassert.Equal(t, \"MISS\", r1.cacheStatus)\n\tassert.Equal(t, string(upstream.Body), string(r1.body))\n\n\tr2 := client.get(\"/another/llamas\", \"Content-Location: /llamas/rock\")\n\tassert.Equal(t, \"HIT\", r2.cacheStatus)\n\tassert.Equal(t, string(upstream.Body), string(r2.body))\n}\n\nfunc TestSpecMultipleCacheControlHeaders(t *testing.T) {\n\tclient, upstream := testSetup()\n\tupstream.Header.Add(\"Cache-Control\", \"max-age=60, max-stale=10\")\n\tupstream.Header.Add(\"Cache-Control\", \"no-cache\")\n\n\tr1 := client.get(\"/\")\n\tassert.Equal(t, \"SKIP\", r1.cacheStatus)\n}\n"
  },
  {
    "path": "util_test.go",
    "content": "package httpcache_test\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/lox/httpcache\"\n)\n\nfunc newRequest(method, url string, h ...string) *http.Request {\n\treq, err := http.NewRequest(method, url, strings.NewReader(\"\"))\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treq.Header = parseHeaders(h)\n\treq.RemoteAddr = \"test.local\"\n\treturn req\n}\n\nfunc newResponse(status int, body []byte, h ...string) *http.Response {\n\treturn &http.Response{\n\t\tStatus:        fmt.Sprintf(\"%d %s\", status, http.StatusText(status)),\n\t\tStatusCode:    status,\n\t\tProto:         \"HTTP/1.1\",\n\t\tProtoMajor:    1,\n\t\tProtoMinor:    1,\n\t\tContentLength: int64(len(body)),\n\t\tBody:          ioutil.NopCloser(bytes.NewReader(body)),\n\t\tHeader:        parseHeaders(h),\n\t\tClose:         true,\n\t}\n}\n\nfunc parseHeaders(input []string) http.Header {\n\theaders := http.Header{}\n\tfor _, header := range input {\n\t\tif idx := strings.Index(header, \": \"); idx != -1 {\n\t\t\theaders.Add(header[0:idx], strings.TrimSpace(header[idx+1:]))\n\t\t}\n\t}\n\treturn headers\n}\n\ntype client struct {\n\thandler      http.Handler\n\tcacheHandler *httpcache.Handler\n}\n\nfunc (c *client) do(r *http.Request) *clientResponse {\n\trec := httptest.NewRecorder()\n\tc.handler.ServeHTTP(rec, r)\n\trec.Flush()\n\n\tvar age int\n\tvar err error\n\n\tif ageHeader := rec.HeaderMap.Get(\"Age\"); ageHeader != \"\" {\n\t\tage, err = strconv.Atoi(ageHeader)\n\t\tif err != nil {\n\t\t\tpanic(\"Can't parse age header\")\n\t\t}\n\t}\n\n\t// wait for writes to finish\n\thttpcache.Writes.Wait()\n\n\treturn &clientResponse{\n\t\tResponseRecorder: rec,\n\t\tcacheStatus:      rec.HeaderMap.Get(httpcache.CacheHeader),\n\t\tstatusCode:       rec.Code,\n\t\tage:              time.Second * time.Duration(age),\n\t\tbody:             rec.Body.Bytes(),\n\t\theader:           rec.HeaderMap,\n\t}\n}\n\nfunc (c *client) get(path string, headers ...string) *clientResponse {\n\treturn c.do(newRequest(\"GET\", \"http://example.org\"+path, headers...))\n}\n\nfunc (c *client) head(path string, headers ...string) *clientResponse {\n\treturn c.do(newRequest(\"HEAD\", \"http://example.org\"+path, headers...))\n}\n\nfunc (c *client) put(path string, headers ...string) *clientResponse {\n\treturn c.do(newRequest(\"PUT\", \"http://example.org\"+path, headers...))\n}\n\nfunc (c *client) post(path string, headers ...string) *clientResponse {\n\treturn c.do(newRequest(\"POST\", \"http://example.org\"+path, headers...))\n}\n\ntype clientResponse struct {\n\t*httptest.ResponseRecorder\n\tcacheStatus string\n\tstatusCode  int\n\tage         time.Duration\n\tbody        []byte\n\theader      http.Header\n}\n\ntype upstreamServer struct {\n\tNow              time.Time\n\tBody             []byte\n\tFilename         string\n\tCacheControl     string\n\tEtag, Vary       string\n\tLastModified     time.Time\n\tResponseDuration time.Duration\n\tStatusCode       int\n\tHeader           http.Header\n\tasserts          []func(r *http.Request)\n\trequests         int\n}\n\nfunc (u *upstreamServer) timeTravel(d time.Duration) {\n\tu.Now = u.Now.Add(d)\n}\n\nfunc (u *upstreamServer) assert(f func(r *http.Request)) {\n\tu.asserts = append(u.asserts, f)\n}\n\nfunc (u *upstreamServer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {\n\tu.requests = u.requests + 1\n\n\tfor _, assertf := range u.asserts {\n\t\tassertf(req)\n\t}\n\n\tif !u.Now.IsZero() {\n\t\trw.Header().Set(\"Date\", u.Now.Format(http.TimeFormat))\n\t}\n\n\tif u.CacheControl != \"\" {\n\t\trw.Header().Set(\"Cache-Control\", u.CacheControl)\n\t}\n\n\tif u.Etag != \"\" {\n\t\trw.Header().Set(\"Etag\", u.Etag)\n\t}\n\n\tif u.Vary != \"\" {\n\t\trw.Header().Set(\"Vary\", u.Vary)\n\t}\n\n\tif u.Header != nil {\n\t\tfor key, headers := range u.Header {\n\t\t\tfor _, header := range headers {\n\t\t\t\trw.Header().Add(key, header)\n\t\t\t}\n\t\t}\n\t}\n\n\tu.timeTravel(u.ResponseDuration)\n\n\tif u.StatusCode != 0 && u.StatusCode != 200 {\n\t\trw.WriteHeader(u.StatusCode)\n\t\tio.Copy(rw, bytes.NewReader(u.Body))\n\t} else {\n\t\thttp.ServeContent(rw, req, u.Filename, u.LastModified, bytes.NewReader(u.Body))\n\t}\n}\n\nfunc (u *upstreamServer) RoundTrip(req *http.Request) (*http.Response, error) {\n\trec := httptest.NewRecorder()\n\tu.ServeHTTP(rec, req)\n\trec.Flush()\n\n\tresp := newResponse(rec.Code, rec.Body.Bytes())\n\tresp.Header = rec.HeaderMap\n\treturn resp, nil\n}\n\nfunc cc(cc string) string {\n\treturn fmt.Sprintf(\"Cache-Control: %s\", cc)\n}\n\nfunc readAll(r io.Reader) []byte {\n\tb, err := ioutil.ReadAll(r)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn b\n}\n\nfunc readAllString(r io.Reader) string {\n\treturn string(readAll(r))\n}\n"
  },
  {
    "path": "validator.go",
    "content": "package httpcache\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n)\n\ntype Validator struct {\n\tHandler http.Handler\n}\n\nfunc (v *Validator) Validate(req *http.Request, res *Resource) bool {\n\toutreq := cloneRequest(req)\n\tresHeaders := res.Header()\n\n\tif etag := resHeaders.Get(\"Etag\"); etag != \"\" {\n\t\toutreq.Header.Set(\"If-None-Match\", etag)\n\t} else if lastMod := resHeaders.Get(\"Last-Modified\"); lastMod != \"\" {\n\t\toutreq.Header.Set(\"If-Modified-Since\", lastMod)\n\t}\n\n\tt := Clock()\n\tresp := httptest.NewRecorder()\n\tv.Handler.ServeHTTP(resp, outreq)\n\tresp.Flush()\n\n\tif age, err := correctedAge(resp.HeaderMap, t, Clock()); err == nil {\n\t\tresp.Header().Set(\"Age\", fmt.Sprintf(\"%.f\", age.Seconds()))\n\t}\n\n\tif headersEqual(resHeaders, resp.HeaderMap) {\n\t\tres.header = resp.HeaderMap\n\t\tres.header.Set(ProxyDateHeader, Clock().Format(http.TimeFormat))\n\t\treturn true\n\t}\n\n\treturn false\n}\n\nvar validationHeaders = []string{\"ETag\", \"Content-MD5\", \"Last-Modified\", \"Content-Length\"}\n\nfunc headersEqual(h1, h2 http.Header) bool {\n\tfor _, header := range validationHeaders {\n\t\tif value := h2.Get(header); value != \"\" {\n\t\t\tif h1.Get(header) != value {\n\t\t\t\tdebugf(\"%s changed, %q != %q\", header, value, h1.Get(header))\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t}\n\n\treturn true\n}\n\n// cloneRequest returns a clone of the provided *http.Request.\n// The clone is a shallow copy of the struct and its Header map.\nfunc cloneRequest(r *http.Request) *http.Request {\n\tr2 := new(http.Request)\n\t*r2 = *r\n\tr2.Header = make(http.Header)\n\tfor k, s := range r.Header {\n\t\tr2.Header[k] = s\n\t}\n\treturn r2\n}\n"
  },
  {
    "path": "vendor/github.com/rainycape/vfs/LICENSE",
    "content": "Mozilla Public License Version 2.0\n==================================\n\n1. Definitions\n--------------\n\n1.1. \"Contributor\"\n    means each individual or legal entity that creates, contributes to\n    the creation of, or owns Covered Software.\n\n1.2. \"Contributor Version\"\n    means the combination of the Contributions of others (if any) used\n    by a Contributor and that particular Contributor's Contribution.\n\n1.3. \"Contribution\"\n    means Covered Software of a particular Contributor.\n\n1.4. \"Covered Software\"\n    means Source Code Form to which the initial Contributor has attached\n    the notice in Exhibit A, the Executable Form of such Source Code\n    Form, and Modifications of such Source Code Form, in each case\n    including portions thereof.\n\n1.5. \"Incompatible With Secondary Licenses\"\n    means\n\n    (a) that the initial Contributor has attached the notice described\n        in Exhibit B to the Covered Software; or\n\n    (b) that the Covered Software was made available under the terms of\n        version 1.1 or earlier of the License, but not also under the\n        terms of a Secondary License.\n\n1.6. \"Executable Form\"\n    means any form of the work other than Source Code Form.\n\n1.7. \"Larger Work\"\n    means a work that combines Covered Software with other material, in \n    a separate file or files, that is not Covered Software.\n\n1.8. \"License\"\n    means this document.\n\n1.9. \"Licensable\"\n    means having the right to grant, to the maximum extent possible,\n    whether at the time of the initial grant or subsequently, any and\n    all of the rights conveyed by this License.\n\n1.10. \"Modifications\"\n    means any of the following:\n\n    (a) any file in Source Code Form that results from an addition to,\n        deletion from, or modification of the contents of Covered\n        Software; or\n\n    (b) any new file in Source Code Form that contains any Covered\n        Software.\n\n1.11. \"Patent Claims\" of a Contributor\n    means any patent claim(s), including without limitation, method,\n    process, and apparatus claims, in any patent Licensable by such\n    Contributor that would be infringed, but for the grant of the\n    License, by the making, using, selling, offering for sale, having\n    made, import, or transfer of either its Contributions or its\n    Contributor Version.\n\n1.12. \"Secondary License\"\n    means either the GNU General Public License, Version 2.0, the GNU\n    Lesser General Public License, Version 2.1, the GNU Affero General\n    Public License, Version 3.0, or any later versions of those\n    licenses.\n\n1.13. \"Source Code Form\"\n    means the form of the work preferred for making modifications.\n\n1.14. \"You\" (or \"Your\")\n    means an individual or a legal entity exercising rights under this\n    License. For legal entities, \"You\" includes any entity that\n    controls, is controlled by, or is under common control with You. For\n    purposes of this definition, \"control\" means (a) the power, direct\n    or indirect, to cause the direction or management of such entity,\n    whether by contract or otherwise, or (b) ownership of more than\n    fifty percent (50%) of the outstanding shares or beneficial\n    ownership of such entity.\n\n2. License Grants and Conditions\n--------------------------------\n\n2.1. Grants\n\nEach Contributor hereby grants You a world-wide, royalty-free,\nnon-exclusive license:\n\n(a) under intellectual property rights (other than patent or trademark)\n    Licensable by such Contributor to use, reproduce, make available,\n    modify, display, perform, distribute, and otherwise exploit its\n    Contributions, either on an unmodified basis, with Modifications, or\n    as part of a Larger Work; and\n\n(b) under Patent Claims of such Contributor to make, use, sell, offer\n    for sale, have made, import, and otherwise transfer either its\n    Contributions or its Contributor Version.\n\n2.2. Effective Date\n\nThe licenses granted in Section 2.1 with respect to any Contribution\nbecome effective for each Contribution on the date the Contributor first\ndistributes such Contribution.\n\n2.3. Limitations on Grant Scope\n\nThe licenses granted in this Section 2 are the only rights granted under\nthis License. No additional rights or licenses will be implied from the\ndistribution or licensing of Covered Software under this License.\nNotwithstanding Section 2.1(b) above, no patent license is granted by a\nContributor:\n\n(a) for any code that a Contributor has removed from Covered Software;\n    or\n\n(b) for infringements caused by: (i) Your and any other third party's\n    modifications of Covered Software, or (ii) the combination of its\n    Contributions with other software (except as part of its Contributor\n    Version); or\n\n(c) under Patent Claims infringed by Covered Software in the absence of\n    its Contributions.\n\nThis License does not grant any rights in the trademarks, service marks,\nor logos of any Contributor (except as may be necessary to comply with\nthe notice requirements in Section 3.4).\n\n2.4. Subsequent Licenses\n\nNo Contributor makes additional grants as a result of Your choice to\ndistribute the Covered Software under a subsequent version of this\nLicense (see Section 10.2) or under the terms of a Secondary License (if\npermitted under the terms of Section 3.3).\n\n2.5. Representation\n\nEach Contributor represents that the Contributor believes its\nContributions are its original creation(s) or it has sufficient rights\nto grant the rights to its Contributions conveyed by this License.\n\n2.6. Fair Use\n\nThis License is not intended to limit any rights You have under\napplicable copyright doctrines of fair use, fair dealing, or other\nequivalents.\n\n2.7. Conditions\n\nSections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted\nin Section 2.1.\n\n3. Responsibilities\n-------------------\n\n3.1. Distribution of Source Form\n\nAll distribution of Covered Software in Source Code Form, including any\nModifications that You create or to which You contribute, must be under\nthe terms of this License. You must inform recipients that the Source\nCode Form of the Covered Software is governed by the terms of this\nLicense, and how they can obtain a copy of this License. You may not\nattempt to alter or restrict the recipients' rights in the Source Code\nForm.\n\n3.2. Distribution of Executable Form\n\nIf You distribute Covered Software in Executable Form then:\n\n(a) such Covered Software must also be made available in Source Code\n    Form, as described in Section 3.1, and You must inform recipients of\n    the Executable Form how they can obtain a copy of such Source Code\n    Form by reasonable means in a timely manner, at a charge no more\n    than the cost of distribution to the recipient; and\n\n(b) You may distribute such Executable Form under the terms of this\n    License, or sublicense it under different terms, provided that the\n    license for the Executable Form does not attempt to limit or alter\n    the recipients' rights in the Source Code Form under this License.\n\n3.3. Distribution of a Larger Work\n\nYou may create and distribute a Larger Work under terms of Your choice,\nprovided that You also comply with the requirements of this License for\nthe Covered Software. If the Larger Work is a combination of Covered\nSoftware with a work governed by one or more Secondary Licenses, and the\nCovered Software is not Incompatible With Secondary Licenses, this\nLicense permits You to additionally distribute such Covered Software\nunder the terms of such Secondary License(s), so that the recipient of\nthe Larger Work may, at their option, further distribute the Covered\nSoftware under the terms of either this License or such Secondary\nLicense(s).\n\n3.4. Notices\n\nYou may not remove or alter the substance of any license notices\n(including copyright notices, patent notices, disclaimers of warranty,\nor limitations of liability) contained within the Source Code Form of\nthe Covered Software, except that You may alter any license notices to\nthe extent required to remedy known factual inaccuracies.\n\n3.5. Application of Additional Terms\n\nYou may choose to offer, and to charge a fee for, warranty, support,\nindemnity or liability obligations to one or more recipients of Covered\nSoftware. However, You may do so only on Your own behalf, and not on\nbehalf of any Contributor. You must make it absolutely clear that any\nsuch warranty, support, indemnity, or liability obligation is offered by\nYou alone, and You hereby agree to indemnify every Contributor for any\nliability incurred by such Contributor as a result of warranty, support,\nindemnity or liability terms You offer. You may include additional\ndisclaimers of warranty and limitations of liability specific to any\njurisdiction.\n\n4. Inability to Comply Due to Statute or Regulation\n---------------------------------------------------\n\nIf it is impossible for You to comply with any of the terms of this\nLicense with respect to some or all of the Covered Software due to\nstatute, judicial order, or regulation then You must: (a) comply with\nthe terms of this License to the maximum extent possible; and (b)\ndescribe the limitations and the code they affect. Such description must\nbe placed in a text file included with all distributions of the Covered\nSoftware under this License. Except to the extent prohibited by statute\nor regulation, such description must be sufficiently detailed for a\nrecipient of ordinary skill to be able to understand it.\n\n5. Termination\n--------------\n\n5.1. The rights granted under this License will terminate automatically\nif You fail to comply with any of its terms. However, if You become\ncompliant, then the rights granted under this License from a particular\nContributor are reinstated (a) provisionally, unless and until such\nContributor explicitly and finally terminates Your grants, and (b) on an\nongoing basis, if such Contributor fails to notify You of the\nnon-compliance by some reasonable means prior to 60 days after You have\ncome back into compliance. Moreover, Your grants from a particular\nContributor are reinstated on an ongoing basis if such Contributor\nnotifies You of the non-compliance by some reasonable means, this is the\nfirst time You have received notice of non-compliance with this License\nfrom such Contributor, and You become compliant prior to 30 days after\nYour receipt of the notice.\n\n5.2. If You initiate litigation against any entity by asserting a patent\ninfringement claim (excluding declaratory judgment actions,\ncounter-claims, and cross-claims) alleging that a Contributor Version\ndirectly or indirectly infringes any patent, then the rights granted to\nYou by any and all Contributors for the Covered Software under Section\n2.1 of this License shall terminate.\n\n5.3. In the event of termination under Sections 5.1 or 5.2 above, all\nend user license agreements (excluding distributors and resellers) which\nhave been validly granted by You or Your distributors under this License\nprior to termination shall survive termination.\n\n************************************************************************\n*                                                                      *\n*  6. Disclaimer of Warranty                                           *\n*  -------------------------                                           *\n*                                                                      *\n*  Covered Software is provided under this License on an \"as is\"       *\n*  basis, without warranty of any kind, either expressed, implied, or  *\n*  statutory, including, without limitation, warranties that the       *\n*  Covered Software is free of defects, merchantable, fit for a        *\n*  particular purpose or non-infringing. The entire risk as to the     *\n*  quality and performance of the Covered Software is with You.        *\n*  Should any Covered Software prove defective in any respect, You     *\n*  (not any Contributor) assume the cost of any necessary servicing,   *\n*  repair, or correction. This disclaimer of warranty constitutes an   *\n*  essential part of this License. No use of any Covered Software is   *\n*  authorized under this License except under this disclaimer.         *\n*                                                                      *\n************************************************************************\n\n************************************************************************\n*                                                                      *\n*  7. Limitation of Liability                                          *\n*  --------------------------                                          *\n*                                                                      *\n*  Under no circumstances and under no legal theory, whether tort      *\n*  (including negligence), contract, or otherwise, shall any           *\n*  Contributor, or anyone who distributes Covered Software as          *\n*  permitted above, be liable to You for any direct, indirect,         *\n*  special, incidental, or consequential damages of any character      *\n*  including, without limitation, damages for lost profits, loss of    *\n*  goodwill, work stoppage, computer failure or malfunction, or any    *\n*  and all other commercial damages or losses, even if such party      *\n*  shall have been informed of the possibility of such damages. This   *\n*  limitation of liability shall not apply to liability for death or   *\n*  personal injury resulting from such party's negligence to the       *\n*  extent applicable law prohibits such limitation. Some               *\n*  jurisdictions do not allow the exclusion or limitation of           *\n*  incidental or consequential damages, so this exclusion and          *\n*  limitation may not apply to You.                                    *\n*                                                                      *\n************************************************************************\n\n8. Litigation\n-------------\n\nAny litigation relating to this License may be brought only in the\ncourts of a jurisdiction where the defendant maintains its principal\nplace of business and such litigation shall be governed by laws of that\njurisdiction, without reference to its conflict-of-law provisions.\nNothing in this Section shall prevent a party's ability to bring\ncross-claims or counter-claims.\n\n9. Miscellaneous\n----------------\n\nThis License represents the complete agreement concerning the subject\nmatter hereof. If any provision of this License is held to be\nunenforceable, such provision shall be reformed only to the extent\nnecessary to make it enforceable. Any law or regulation which provides\nthat the language of a contract shall be construed against the drafter\nshall not be used to construe this License against a Contributor.\n\n10. Versions of the License\n---------------------------\n\n10.1. New Versions\n\nMozilla Foundation is the license steward. Except as provided in Section\n10.3, no one other than the license steward has the right to modify or\npublish new versions of this License. Each version will be given a\ndistinguishing version number.\n\n10.2. Effect of New Versions\n\nYou may distribute the Covered Software under the terms of the version\nof the License under which You originally received the Covered Software,\nor under the terms of any subsequent version published by the license\nsteward.\n\n10.3. Modified Versions\n\nIf you create software not governed by this License, and you want to\ncreate a new license for such software, you may create and use a\nmodified version of this License if you rename the license and remove\nany references to the name of the license steward (except to note that\nsuch modified license differs from this License).\n\n10.4. Distributing Source Code Form that is Incompatible With Secondary\nLicenses\n\nIf You choose to distribute Source Code Form that is Incompatible With\nSecondary Licenses under the terms of this version of the License, the\nnotice described in Exhibit B of this License must be attached.\n\nExhibit A - Source Code Form License Notice\n-------------------------------------------\n\n  This Source Code Form is subject to the terms of the Mozilla Public\n  License, v. 2.0. If a copy of the MPL was not distributed with this\n  file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\nIf it is not possible or desirable to put the notice in a particular\nfile, then You may include the notice in a location (such as a LICENSE\nfile in a relevant directory) where a recipient would be likely to look\nfor such a notice.\n\nYou may add additional accurate notices of copyright ownership.\n\nExhibit B - \"Incompatible With Secondary Licenses\" Notice\n---------------------------------------------------------\n\n  This Source Code Form is \"Incompatible With Secondary Licenses\", as\n  defined by the Mozilla Public License, v. 2.0.\n"
  },
  {
    "path": "vendor/github.com/rainycape/vfs/README.md",
    "content": "# vfs\n\nvfs implements Virtual File Systems with read-write support in Go (golang)\n\n[![GoDoc](https://godoc.org/github.com/rainycape/vfs?status.svg)](https://godoc.org/github.com/rainycape/vfs)\n"
  },
  {
    "path": "vendor/github.com/rainycape/vfs/bench_test.go",
    "content": "package vfs\n\nimport (\n\t\"bytes\"\n\t\"compress/gzip\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"testing\"\n)\n\nfunc BenchmarkLoadGoSrc(b *testing.B) {\n\tf := openOptionalTestFile(b, goTestFile)\n\tdefer f.Close()\n\t// Decompress to avoid measuring the time to gunzip\n\tzr, err := gzip.NewReader(f)\n\tif err != nil {\n\t\tb.Fatal(err)\n\t}\n\tdefer zr.Close()\n\tdata, err := ioutil.ReadAll(zr)\n\tif err != nil {\n\t\tb.Fatal(err)\n\t}\n\tb.ResetTimer()\n\tfor ii := 0; ii < b.N; ii++ {\n\t\tif _, err := Tar(bytes.NewReader(data)); err != nil {\n\t\t\tb.Fatal(err)\n\t\t}\n\t}\n}\n\nfunc BenchmarkWalkGoSrc(b *testing.B) {\n\tf := openOptionalTestFile(b, goTestFile)\n\tdefer f.Close()\n\tfs, err := TarGzip(f)\n\tif err != nil {\n\t\tb.Fatal(err)\n\t}\n\tb.ResetTimer()\n\tfor ii := 0; ii < b.N; ii++ {\n\t\tWalk(fs, \"/\", func(_ VFS, _ string, _ os.FileInfo, _ error) error { return nil })\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/rainycape/vfs/chroot.go",
    "content": "package vfs\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path\"\n)\n\ntype chrootFileSystem struct {\n\troot string\n\tfs   VFS\n}\n\nfunc (fs *chrootFileSystem) path(p string) string {\n\t// root always ends with /, if there are double\n\t// slashes they will be fixed by the underlying\n\t// VFS\n\treturn fs.root + p\n}\n\nfunc (fs *chrootFileSystem) VFS() VFS {\n\treturn fs.fs\n}\n\nfunc (fs *chrootFileSystem) Open(path string) (RFile, error) {\n\treturn fs.fs.Open(fs.path(path))\n}\n\nfunc (fs *chrootFileSystem) OpenFile(path string, flag int, perm os.FileMode) (WFile, error) {\n\treturn fs.fs.OpenFile(fs.path(path), flag, perm)\n}\n\nfunc (fs *chrootFileSystem) Lstat(path string) (os.FileInfo, error) {\n\treturn fs.fs.Lstat(fs.path(path))\n}\n\nfunc (fs *chrootFileSystem) Stat(path string) (os.FileInfo, error) {\n\treturn fs.fs.Stat(fs.path(path))\n}\n\nfunc (fs *chrootFileSystem) ReadDir(path string) ([]os.FileInfo, error) {\n\treturn fs.fs.ReadDir(fs.path(path))\n}\n\nfunc (fs *chrootFileSystem) Mkdir(path string, perm os.FileMode) error {\n\treturn fs.fs.Mkdir(fs.path(path), perm)\n}\n\nfunc (fs *chrootFileSystem) Remove(path string) error {\n\treturn fs.fs.Remove(fs.path(path))\n}\n\nfunc (fs *chrootFileSystem) String() string {\n\treturn fmt.Sprintf(\"Chroot %s %s\", fs.root, fs.fs.String())\n}\n\n// Chroot returns a new VFS wrapping the given VFS, making the given\n// directory the new root (\"/\"). Note that root must be an existing\n// directory in the given file system, otherwise an error is returned.\nfunc Chroot(root string, fs VFS) (VFS, error) {\n\troot = path.Clean(\"/\" + root)\n\tst, err := fs.Stat(root)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif !st.IsDir() {\n\t\treturn nil, fmt.Errorf(\"%s is not a directory\", root)\n\t}\n\treturn &chrootFileSystem{root: root + \"/\", fs: fs}, nil\n}\n"
  },
  {
    "path": "vendor/github.com/rainycape/vfs/doc.go",
    "content": "// Package vfs implements Virtual File Systems with read-write support.\n//\n// All implementatations use slash ('/') separated paths, with / representing\n// the root directory. This means that to manipulate or construct paths, the\n// functions in path package should be used, like path.Join or path.Dir.\n// There's also no notion of the current directory nor relative paths. The paths\n// /a/b/c and a/b/c are considered to point to the same element.\n//\n// This package also implements some shorthand functions which might be used with\n// any VFS implementation, providing the same functionality than functions in the\n// io/ioutil, os and path/filepath packages:\n//\n//  io/ioutil.ReadFile => ReadFile\n//  io/ioutil.WriteFile => WriteFile\n//  os.IsExist => IsExist\n//  os.IsNotExist => IsNotExist\n//  os.MkdirAll => MkdirAll\n//  os.RemoveAll => RemoveAll\n//  path/filepath.Walk => Walk\n//\n// All VFS implementations are thread safe, so multiple readers and writers might\n// operate on them at any time.\npackage vfs\n"
  },
  {
    "path": "vendor/github.com/rainycape/vfs/file.go",
    "content": "package vfs\n\nimport (\n\t\"os\"\n\t\"path\"\n\t\"sync\"\n\t\"time\"\n)\n\n// EntryType indicates the type of the entry.\ntype EntryType uint8\n\nconst (\n\t// EntryTypeFile indicates the entry is a file.\n\tEntryTypeFile EntryType = iota + 1\n\t// EntryTypeDir indicates the entry is a directory.\n\tEntryTypeDir\n)\n\nconst (\n\tModeCompress os.FileMode = 1 << 16\n)\n\n// Entry is the interface implemented by the in-memory representations\n// of files and directories.\ntype Entry interface {\n\t// Type returns the entry type, either EntryTypeFile or\n\t// EntryTypeDir.\n\tType() EntryType\n\t// Size returns the file size. For directories, it's always zero.\n\tSize() int64\n\t// FileMode returns the file mode as an os.FileMode.\n\tFileMode() os.FileMode\n\t// ModificationTime returns the last time the file or the directory\n\t// was modified.\n\tModificationTime() time.Time\n}\n\n// Type File represents an in-memory file. Most in-memory VFS implementations\n// should use this structure to represent their files, in order to save work.\ntype File struct {\n\tsync.RWMutex\n\t// Data contains the file data.\n\tData []byte\n\t// Mode is the file or directory mode. Note that some filesystems\n\t// might ignore the permission bits.\n\tMode os.FileMode\n\t// ModTime represents the last modification time to the file.\n\tModTime time.Time\n}\n\nfunc (f *File) Type() EntryType {\n\treturn EntryTypeFile\n}\n\nfunc (f *File) Size() int64 {\n\tf.RLock()\n\tdefer f.RUnlock()\n\treturn int64(len(f.Data))\n}\n\nfunc (f *File) FileMode() os.FileMode {\n\treturn f.Mode\n}\n\nfunc (f *File) ModificationTime() time.Time {\n\tf.RLock()\n\tdefer f.RUnlock()\n\treturn f.ModTime\n}\n\n// Type Dir represents an in-memory directory. Most in-memory VFS\n// implementations should use this structure to represent their\n// directories, in order to save work.\ntype Dir struct {\n\tsync.RWMutex\n\t// Mode is the file or directory mode. Note that some filesystems\n\t// might ignore the permission bits.\n\tMode os.FileMode\n\t// ModTime represents the last modification time to directory.\n\tModTime time.Time\n\t// Entry names in this directory, in order.\n\tEntryNames []string\n\t// Entries in the same order as EntryNames.\n\tEntries []Entry\n}\n\nfunc (d *Dir) Type() EntryType {\n\treturn EntryTypeDir\n}\n\nfunc (d *Dir) Size() int64 {\n\treturn 0\n}\n\nfunc (d *Dir) FileMode() os.FileMode {\n\treturn d.Mode\n}\n\nfunc (d *Dir) ModificationTime() time.Time {\n\td.RLock()\n\tdefer d.RUnlock()\n\treturn d.ModTime\n}\n\n// Add ads a new entry to the directory. If there's already an\n// entry ith the same name, an error is returned.\nfunc (d *Dir) Add(name string, entry Entry) error {\n\t// TODO: Binary search\n\tfor ii, v := range d.EntryNames {\n\t\tif v > name {\n\t\t\tnames := make([]string, len(d.EntryNames)+1)\n\t\t\tcopy(names, d.EntryNames[:ii])\n\t\t\tnames[ii] = name\n\t\t\tcopy(names[ii+1:], d.EntryNames[ii:])\n\t\t\td.EntryNames = names\n\n\t\t\tentries := make([]Entry, len(d.Entries)+1)\n\t\t\tcopy(entries, d.Entries[:ii])\n\t\t\tentries[ii] = entry\n\t\t\tcopy(entries[ii+1:], d.Entries[ii:])\n\n\t\t\td.Entries = entries\n\t\t\treturn nil\n\t\t}\n\t\tif v == name {\n\t\t\treturn os.ErrExist\n\t\t}\n\t}\n\t// Not added yet, put at the end\n\td.EntryNames = append(d.EntryNames, name)\n\td.Entries = append(d.Entries, entry)\n\treturn nil\n}\n\n// Find returns the entry with the given name and its index,\n// or an error if an entry with that name does not exist in\n// the directory.\nfunc (d *Dir) Find(name string) (Entry, int, error) {\n\tfor ii, v := range d.EntryNames {\n\t\tif v == name {\n\t\t\treturn d.Entries[ii], ii, nil\n\t\t}\n\t}\n\treturn nil, -1, os.ErrNotExist\n}\n\n// EntryInfo implements the os.FileInfo interface wrapping\n// a given File and its Path in its VFS.\ntype EntryInfo struct {\n\t// Path is the full path to the entry in its VFS.\n\tPath string\n\t// Entry is the instance used by the VFS to represent\n\t// the in-memory entry.\n\tEntry Entry\n}\n\nfunc (info *EntryInfo) Name() string {\n\treturn path.Base(info.Path)\n}\n\nfunc (info *EntryInfo) Size() int64 {\n\treturn info.Entry.Size()\n}\n\nfunc (info *EntryInfo) Mode() os.FileMode {\n\treturn info.Entry.FileMode()\n}\n\nfunc (info *EntryInfo) ModTime() time.Time {\n\treturn info.Entry.ModificationTime()\n}\n\nfunc (info *EntryInfo) IsDir() bool {\n\treturn info.Entry.Type() == EntryTypeDir\n}\n\n// Sys returns the underlying Entry.\nfunc (info *EntryInfo) Sys() interface{} {\n\treturn info.Entry\n}\n\n// FileInfos represents an slice of os.FileInfo which\n// implements the sort.Interface. This type is only\n// exported for users who want to implement their own\n// filesystems, since VFS.ReadDir requires the returned\n// []os.FileInfo to be sorted by name.\ntype FileInfos []os.FileInfo\n\nfunc (f FileInfos) Len() int {\n\treturn len(f)\n}\n\nfunc (f FileInfos) Less(i, j int) bool {\n\treturn f[i].Name() < f[j].Name()\n}\n\nfunc (f FileInfos) Swap(i, j int) {\n\tf[i], f[j] = f[j], f[i]\n}\n"
  },
  {
    "path": "vendor/github.com/rainycape/vfs/file_util.go",
    "content": "package vfs\n\nimport (\n\t\"bytes\"\n\t\"compress/zlib\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"runtime\"\n\t\"time\"\n)\n\nvar (\n\terrFileClosed = errors.New(\"file is closed\")\n)\n\n// NewRFile returns a RFile from a *File.\nfunc NewRFile(f *File) (RFile, error) {\n\tdata, err := fileData(f)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &file{f: f, data: data, readable: true}, nil\n}\n\n// NewWFile returns a WFile from a *File.\nfunc NewWFile(f *File, read bool, write bool) (WFile, error) {\n\tdata, err := fileData(f)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tw := &file{f: f, data: data, readable: read, writable: write}\n\truntime.SetFinalizer(w, closeFile)\n\treturn w, nil\n}\n\nfunc closeFile(f *file) {\n\tf.Close()\n}\n\nfunc fileData(f *File) ([]byte, error) {\n\tif len(f.Data) == 0 || f.Mode&ModeCompress == 0 {\n\t\treturn f.Data, nil\n\t}\n\tzr, err := zlib.NewReader(bytes.NewReader(f.Data))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer zr.Close()\n\tvar out bytes.Buffer\n\tif _, err := io.Copy(&out, zr); err != nil {\n\t\treturn nil, err\n\t}\n\treturn out.Bytes(), nil\n}\n\ntype file struct {\n\tf        *File\n\tdata     []byte\n\toffset   int\n\treadable bool\n\twritable bool\n\tclosed   bool\n}\n\nfunc (f *file) Read(p []byte) (int, error) {\n\tif !f.readable {\n\t\treturn 0, ErrWriteOnly\n\t}\n\tf.f.RLock()\n\tdefer f.f.RUnlock()\n\tif f.closed {\n\t\treturn 0, errFileClosed\n\t}\n\tif f.offset > len(f.data) {\n\t\treturn 0, io.EOF\n\t}\n\tn := copy(p, f.data[f.offset:])\n\tf.offset += n\n\tif n < len(p) {\n\t\treturn n, io.EOF\n\t}\n\treturn n, nil\n}\n\nfunc (f *file) Seek(offset int64, whence int) (int64, error) {\n\tf.f.Lock()\n\tdefer f.f.Unlock()\n\tif f.closed {\n\t\treturn 0, errFileClosed\n\t}\n\tswitch whence {\n\tcase os.SEEK_SET:\n\t\tf.offset = int(offset)\n\tcase os.SEEK_CUR:\n\t\tf.offset += int(offset)\n\tcase os.SEEK_END:\n\t\tf.offset = len(f.data) + int(offset)\n\tdefault:\n\t\tpanic(fmt.Errorf(\"Seek: invalid whence %d\", whence))\n\t}\n\tif f.offset > len(f.data) {\n\t\tf.offset = len(f.data)\n\t} else if f.offset < 0 {\n\t\tf.offset = 0\n\t}\n\treturn int64(f.offset), nil\n}\n\nfunc (f *file) Write(p []byte) (int, error) {\n\tif !f.writable {\n\t\treturn 0, ErrReadOnly\n\t}\n\tf.f.Lock()\n\tdefer f.f.Unlock()\n\tif f.closed {\n\t\treturn 0, errFileClosed\n\t}\n\tcount := len(p)\n\tn := copy(f.data[f.offset:], p)\n\tif n < count {\n\t\tf.data = append(f.data, p[n:]...)\n\t}\n\tf.offset += count\n\tf.f.ModTime = time.Now()\n\treturn count, nil\n}\n\nfunc (f *file) Close() error {\n\tif !f.closed {\n\t\tf.f.Lock()\n\t\tdefer f.f.Unlock()\n\t\tif !f.closed {\n\t\t\tif f.f.Mode&ModeCompress != 0 {\n\t\t\t\tvar buf bytes.Buffer\n\t\t\t\tzw := zlib.NewWriter(&buf)\n\t\t\t\tif _, err := zw.Write(f.data); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tif err := zw.Close(); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tif buf.Len() < len(f.data) {\n\t\t\t\t\tf.f.Data = buf.Bytes()\n\t\t\t\t} else {\n\t\t\t\t\tf.f.Mode &= ^ModeCompress\n\t\t\t\t\tf.f.Data = f.data\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tf.f.Data = f.data\n\t\t\t}\n\t\t\tf.closed = true\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (f *file) IsCompressed() bool {\n\treturn f.f.Mode&ModeCompress != 0\n}\n\nfunc (f *file) SetCompressed(c bool) {\n\tf.f.Lock()\n\tdefer f.f.Unlock()\n\tif c {\n\t\tf.f.Mode |= ModeCompress\n\t} else {\n\t\tf.f.Mode &= ^ModeCompress\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/rainycape/vfs/fs.go",
    "content": "package vfs\n\nimport (\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"path\"\n\t\"path/filepath\"\n)\n\n// IMPORTANT: Note about wrapping os. functions: os.Open, os.OpenFile etc... will return a non-nil\n// interface pointing to a nil instance in case of error (whoever decided this disctintion in Go\n// was a good idea deservers to be hung by his thumbs). This is highly undesirable, since users\n// can't rely on checking f != nil to know if a correct handle was returned. That's why the\n// methods in fileSystem do the error checking themselves and return a true nil in case of error.\n\ntype fileSystem struct {\n\troot      string\n\ttemporary bool\n}\n\nfunc (fs *fileSystem) path(name string) string {\n\tname = path.Clean(\"/\" + name)\n\treturn filepath.Join(fs.root, filepath.FromSlash(name))\n}\n\n// Root returns the root directory of the fileSystem, as an\n// absolute path native to the current operating system.\nfunc (fs *fileSystem) Root() string {\n\treturn fs.root\n}\n\n// IsTemporary returns wheter the fileSystem is temporary.\nfunc (fs *fileSystem) IsTemporary() bool {\n\treturn fs.temporary\n}\n\nfunc (fs *fileSystem) Open(path string) (RFile, error) {\n\tf, err := os.Open(fs.path(path))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn f, nil\n}\n\nfunc (fs *fileSystem) OpenFile(path string, flag int, mode os.FileMode) (WFile, error) {\n\tf, err := os.OpenFile(fs.path(path), flag, mode)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn f, nil\n}\n\nfunc (fs *fileSystem) Lstat(path string) (os.FileInfo, error) {\n\tinfo, err := os.Lstat(fs.path(path))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn info, nil\n}\n\nfunc (fs *fileSystem) Stat(path string) (os.FileInfo, error) {\n\tinfo, err := os.Stat(fs.path(path))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn info, nil\n}\n\nfunc (fs *fileSystem) ReadDir(path string) ([]os.FileInfo, error) {\n\tfiles, err := ioutil.ReadDir(fs.path(path))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn files, nil\n}\n\nfunc (fs *fileSystem) Mkdir(path string, perm os.FileMode) error {\n\treturn os.Mkdir(fs.path(path), perm)\n}\n\nfunc (fs *fileSystem) Remove(path string) error {\n\treturn os.Remove(fs.path(path))\n}\n\nfunc (fs *fileSystem) String() string {\n\treturn fmt.Sprintf(\"fileSystem: %s\", fs.root)\n}\n\n// Close is a no-op on non-temporary filesystems. On temporary\n// ones (as returned by TmpFS), it removes all the temporary files.\nfunc (f *fileSystem) Close() error {\n\tif f.temporary {\n\t\treturn os.RemoveAll(f.root)\n\t}\n\treturn nil\n}\n\nfunc newFS(root string) (*fileSystem, error) {\n\tabs, err := filepath.Abs(root)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &fileSystem{root: abs}, nil\n}\n\n// FS returns a VFS at the given path, which must be provided\n// as native path of the current operating system. The path might be\n// either absolute or relative, but the fileSystem will be anchored\n// at the absolute path represented by root at the time of the function\n// call.\nfunc FS(root string) (VFS, error) {\n\treturn newFS(root)\n}\n\n// TmpFS returns a temporary file system with the given prefix and its root\n// directory name, which might be empty. The temporary file system is created\n// in the default temporary directory for the operating system. Once you're\n// done with the temporary filesystem, you might can all its files by calling\n// its Close method.\nfunc TmpFS(prefix string) (TemporaryVFS, error) {\n\tdir, err := ioutil.TempDir(\"\", prefix)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfs, err := newFS(dir)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfs.temporary = true\n\treturn fs, nil\n}\n"
  },
  {
    "path": "vendor/github.com/rainycape/vfs/map.go",
    "content": "package vfs\n\nimport (\n\t\"path\"\n\t\"sort\"\n)\n\n// Map returns an in-memory file system using the given files argument to\n// populate it (which might be nil). Note that the files map does\n// not need to contain any directories, they will be created automatically.\n// If the files contain conflicting paths (e.g. files named a and a/b, thus\n// making \"a\" both a file and a directory), an error will be returned.\nfunc Map(files map[string]*File) (VFS, error) {\n\tfs := newMemory()\n\tkeys := make([]string, 0, len(files))\n\tfor k := range files {\n\t\tkeys = append(keys, k)\n\t}\n\tsort.Strings(keys)\n\tvar dir *Dir\n\tvar prevDir *Dir\n\tvar prevDirPath string\n\tfor _, k := range keys {\n\t\tfile := files[k]\n\t\tif file.Mode == 0 {\n\t\t\tfile.Mode = 0644\n\t\t}\n\t\tfileDir, fileBase := path.Split(k)\n\t\tif prevDir != nil && fileDir == prevDirPath {\n\t\t\tdir = prevDir\n\t\t} else {\n\t\t\tif err := MkdirAll(fs, fileDir, 0755); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tvar err error\n\t\t\tdir, err = fs.dirEntry(fileDir)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tprevDir = dir\n\t\t\tprevDirPath = fileDir\n\t\t}\n\t\tif err := dir.Add(fileBase, file); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn fs, nil\n}\n"
  },
  {
    "path": "vendor/github.com/rainycape/vfs/mem.go",
    "content": "package vfs\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\tpathpkg \"path\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n)\n\nvar (\n\terrNoEmptyNameFile = errors.New(\"can't create file with empty name\")\n\terrNoEmptyNameDir  = errors.New(\"can't create directory with empty name\")\n)\n\ntype memoryFileSystem struct {\n\tmu   sync.RWMutex\n\troot *Dir\n}\n\n// entry must always be called with the lock held\nfunc (fs *memoryFileSystem) entry(path string) (Entry, *Dir, int, error) {\n\tpath = cleanPath(path)\n\tif path == \"\" || path == \"/\" || path == \".\" {\n\t\treturn fs.root, nil, 0, nil\n\t}\n\tif path[0] == '/' {\n\t\tpath = path[1:]\n\t}\n\tdir := fs.root\n\tfor {\n\t\tp := strings.IndexByte(path, '/')\n\t\tname := path\n\t\tif p > 0 {\n\t\t\tname = path[:p]\n\t\t\tpath = path[p+1:]\n\t\t} else {\n\t\t\tpath = \"\"\n\t\t}\n\t\tdir.RLock()\n\t\tentry, pos, err := dir.Find(name)\n\t\tdir.RUnlock()\n\t\tif err != nil {\n\t\t\treturn nil, nil, 0, err\n\t\t}\n\t\tif len(path) == 0 {\n\t\t\treturn entry, dir, pos, nil\n\t\t}\n\t\tif entry.Type() != EntryTypeDir {\n\t\t\tbreak\n\t\t}\n\t\tdir = entry.(*Dir)\n\t}\n\treturn nil, nil, 0, os.ErrNotExist\n}\n\nfunc (fs *memoryFileSystem) dirEntry(path string) (*Dir, error) {\n\tentry, _, _, err := fs.entry(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif entry.Type() != EntryTypeDir {\n\t\treturn nil, fmt.Errorf(\"%s it's not a directory\", path)\n\t}\n\treturn entry.(*Dir), nil\n}\n\nfunc (fs *memoryFileSystem) Open(path string) (RFile, error) {\n\tentry, _, _, err := fs.entry(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif entry.Type() != EntryTypeFile {\n\t\treturn nil, fmt.Errorf(\"%s is not a file\", path)\n\t}\n\treturn NewRFile(entry.(*File))\n}\n\nfunc (fs *memoryFileSystem) OpenFile(path string, flag int, mode os.FileMode) (WFile, error) {\n\tif mode&os.ModeType != 0 {\n\t\treturn nil, fmt.Errorf(\"%T does not support special files\", fs)\n\t}\n\tpath = cleanPath(path)\n\tdir, base := pathpkg.Split(path)\n\tif base == \"\" {\n\t\treturn nil, errNoEmptyNameFile\n\t}\n\tfs.mu.RLock()\n\td, err := fs.dirEntry(dir)\n\tfs.mu.RUnlock()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\td.Lock()\n\tdefer d.Unlock()\n\tf, _, _ := d.Find(base)\n\tif f == nil && flag&os.O_CREATE == 0 {\n\t\treturn nil, os.ErrNotExist\n\t}\n\t// Read only file?\n\tif flag&os.O_WRONLY == 0 && flag&os.O_RDWR == 0 {\n\t\tif f == nil {\n\t\t\treturn nil, os.ErrNotExist\n\t\t}\n\t\treturn NewWFile(f.(*File), true, false)\n\t}\n\t// Write file, either f != nil or flag&os.O_CREATE\n\tif f != nil {\n\t\tif f.Type() != EntryTypeFile {\n\t\t\treturn nil, fmt.Errorf(\"%s is not a file\", path)\n\t\t}\n\t\tif flag&os.O_EXCL != 0 {\n\t\t\treturn nil, os.ErrExist\n\t\t}\n\t\t// Check if we should truncate\n\t\tif flag&os.O_TRUNC != 0 {\n\t\t\tfile := f.(*File)\n\t\t\tfile.Lock()\n\t\t\tfile.ModTime = time.Now()\n\t\t\tfile.Data = nil\n\t\t\tfile.Unlock()\n\t\t}\n\t} else {\n\t\tf = &File{ModTime: time.Now()}\n\t\td.Add(base, f)\n\t}\n\treturn NewWFile(f.(*File), flag&os.O_RDWR != 0, true)\n}\n\nfunc (fs *memoryFileSystem) Lstat(path string) (os.FileInfo, error) {\n\treturn fs.Stat(path)\n}\n\nfunc (fs *memoryFileSystem) Stat(path string) (os.FileInfo, error) {\n\tentry, _, _, err := fs.entry(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &EntryInfo{Path: path, Entry: entry}, nil\n}\n\nfunc (fs *memoryFileSystem) ReadDir(path string) ([]os.FileInfo, error) {\n\tfs.mu.RLock()\n\tdefer fs.mu.RUnlock()\n\treturn fs.readDir(path)\n}\n\nfunc (fs *memoryFileSystem) readDir(path string) ([]os.FileInfo, error) {\n\tentry, _, _, err := fs.entry(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif entry.Type() != EntryTypeDir {\n\t\treturn nil, fmt.Errorf(\"%s is not a directory\", path)\n\t}\n\tdir := entry.(*Dir)\n\tdir.RLock()\n\tinfos := make([]os.FileInfo, len(dir.Entries))\n\tfor ii, v := range dir.EntryNames {\n\t\tinfos[ii] = &EntryInfo{\n\t\t\tPath:  pathpkg.Join(path, v),\n\t\t\tEntry: dir.Entries[ii],\n\t\t}\n\t}\n\tdir.RUnlock()\n\treturn infos, nil\n}\n\nfunc (fs *memoryFileSystem) Mkdir(path string, perm os.FileMode) error {\n\tpath = cleanPath(path)\n\tdir, base := pathpkg.Split(path)\n\tif base == \"\" {\n\t\tif dir == \"/\" || dir == \"\" {\n\t\t\treturn os.ErrExist\n\t\t}\n\t\treturn errNoEmptyNameDir\n\t}\n\tfs.mu.RLock()\n\td, err := fs.dirEntry(dir)\n\tfs.mu.RUnlock()\n\tif err != nil {\n\t\treturn err\n\t}\n\td.Lock()\n\tdefer d.Unlock()\n\tif _, p, _ := d.Find(base); p >= 0 {\n\t\treturn os.ErrExist\n\t}\n\td.Add(base, &Dir{\n\t\tMode:    os.ModeDir | perm,\n\t\tModTime: time.Now(),\n\t})\n\treturn nil\n}\n\nfunc (fs *memoryFileSystem) Remove(path string) error {\n\tentry, dir, pos, err := fs.entry(path)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif entry.Type() == EntryTypeDir && len(entry.(*Dir).Entries) > 0 {\n\t\treturn fmt.Errorf(\"directory %s not empty\", path)\n\t}\n\t// Lock again, the position might have changed\n\tdir.Lock()\n\t_, pos, err = dir.Find(pathpkg.Base(path))\n\tif err == nil {\n\t\tdir.EntryNames = append(dir.EntryNames[:pos], dir.EntryNames[pos+1:]...)\n\t\tdir.Entries = append(dir.Entries[:pos], dir.Entries[pos+1:]...)\n\t}\n\tdir.Unlock()\n\treturn err\n}\n\nfunc (fs *memoryFileSystem) String() string {\n\treturn \"MemoryFileSystem\"\n}\n\nfunc newMemory() *memoryFileSystem {\n\tfs := &memoryFileSystem{\n\t\troot: &Dir{\n\t\t\tMode:    os.ModeDir | 0755,\n\t\t\tModTime: time.Now(),\n\t\t},\n\t}\n\treturn fs\n}\n\n// Memory returns an empty in memory VFS.\nfunc Memory() VFS {\n\treturn newMemory()\n}\n\nfunc cleanPath(path string) string {\n\treturn strings.Trim(pathpkg.Clean(\"/\"+path), \"/\")\n}\n"
  },
  {
    "path": "vendor/github.com/rainycape/vfs/mounter.go",
    "content": "package vfs\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path\"\n\t\"strings\"\n)\n\nconst (\n\tseparator = \"/\"\n)\n\nfunc hasSubdir(root, dir string) (string, bool) {\n\troot = path.Clean(root)\n\tif !strings.HasSuffix(root, separator) {\n\t\troot += separator\n\t}\n\tdir = path.Clean(dir)\n\tif !strings.HasPrefix(dir, root) {\n\t\treturn \"\", false\n\t}\n\treturn dir[len(root):], true\n}\n\ntype mountPoint struct {\n\tpoint string\n\tfs    VFS\n}\n\nfunc (m *mountPoint) String() string {\n\treturn fmt.Sprintf(\"%s at %s\", m.fs, m.point)\n}\n\n// Mounter implements the VFS interface and allows mounting different virtual\n// file systems at arbitraty points, working much like a UNIX filesystem.\n// Note that the first mounted filesystem must be always at \"/\".\ntype Mounter struct {\n\tpoints []*mountPoint\n}\n\nfunc (m *Mounter) fs(p string) (VFS, string, error) {\n\tfor ii := len(m.points) - 1; ii >= 0; ii-- {\n\t\tif rel, ok := hasSubdir(m.points[ii].point, p); ok {\n\t\t\treturn m.points[ii].fs, rel, nil\n\t\t}\n\t}\n\treturn nil, \"\", os.ErrNotExist\n}\n\n// Mount mounts the given filesystem at the given mount point. Unless the\n// mount point is /, it must be an already existing directory.\nfunc (m *Mounter) Mount(fs VFS, point string) error {\n\tpoint = path.Clean(point)\n\tif point == \".\" || point == \"\" {\n\t\tpoint = \"/\"\n\t}\n\tif point == \"/\" {\n\t\tif len(m.points) > 0 {\n\t\t\treturn fmt.Errorf(\"%s is already mounted at /\", m.points[0])\n\t\t}\n\t\tm.points = append(m.points, &mountPoint{point, fs})\n\t\treturn nil\n\t}\n\tstat, err := m.Stat(point)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif !stat.IsDir() {\n\t\treturn fmt.Errorf(\"%s is not a directory\", point)\n\t}\n\tm.points = append(m.points, &mountPoint{point, fs})\n\treturn nil\n}\n\n// Umount umounts the filesystem from the given mount point. If there are other filesystems\n// mounted below it or there's no filesystem mounted at that point, an error is returned.\nfunc (m *Mounter) Umount(point string) error {\n\tpoint = path.Clean(point)\n\tfor ii, v := range m.points {\n\t\tif v.point == point {\n\t\t\t// Check if we have mount points below this one\n\t\t\tfor _, vv := range m.points[ii:] {\n\t\t\t\tif _, ok := hasSubdir(v.point, vv.point); ok {\n\t\t\t\t\treturn fmt.Errorf(\"can't umount %s because %s is mounted below it\", point, vv)\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.points = append(m.points[:ii], m.points[ii+1:]...)\n\t\t\treturn nil\n\t\t}\n\t}\n\treturn fmt.Errorf(\"no filesystem mounted at %s\", point)\n}\n\nfunc (m *Mounter) Open(path string) (RFile, error) {\n\tfs, p, err := m.fs(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn fs.Open(p)\n}\n\nfunc (m *Mounter) OpenFile(path string, flag int, perm os.FileMode) (WFile, error) {\n\tfs, p, err := m.fs(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn fs.OpenFile(p, flag, perm)\n}\n\nfunc (m *Mounter) Lstat(path string) (os.FileInfo, error) {\n\tfs, p, err := m.fs(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn fs.Lstat(p)\n}\n\nfunc (m *Mounter) Stat(path string) (os.FileInfo, error) {\n\tfs, p, err := m.fs(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn fs.Stat(p)\n}\n\nfunc (m *Mounter) ReadDir(path string) ([]os.FileInfo, error) {\n\tfs, p, err := m.fs(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn fs.ReadDir(p)\n}\n\nfunc (m *Mounter) Mkdir(path string, perm os.FileMode) error {\n\tfs, p, err := m.fs(path)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn fs.Mkdir(p, perm)\n}\n\nfunc (m *Mounter) Remove(path string) error {\n\t// TODO: Don't allow removing an empty directory\n\t// with a mount below it.\n\tfs, p, err := m.fs(path)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn fs.Remove(p)\n}\n\nfunc (m *Mounter) String() string {\n\ts := make([]string, len(m.points))\n\tfor ii, v := range m.points {\n\t\ts[ii] = v.String()\n\t}\n\treturn fmt.Sprintf(\"Mounter: %s\", strings.Join(s, \", \"))\n}\n\nfunc mounterCompileTimeCheck() VFS {\n\treturn &Mounter{}\n}\n"
  },
  {
    "path": "vendor/github.com/rainycape/vfs/open.go",
    "content": "package vfs\n\nimport (\n\t\"archive/tar\"\n\t\"archive/zip\"\n\t\"bytes\"\n\t\"compress/bzip2\"\n\t\"compress/gzip\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n)\n\n// Zip returns an in-memory VFS initialized with the\n// contents of the .zip file read from the given io.Reader.\n// Since archive/zip requires an io.ReaderAt rather than an\n// io.Reader, and a known size, Zip will read the whole file\n// into memory and provide its own buffering if r does not\n// implement io.ReaderAt or size is <= 0.\nfunc Zip(r io.Reader, size int64) (VFS, error) {\n\trat, _ := r.(io.ReaderAt)\n\tif rat == nil || size <= 0 {\n\t\tdata, err := ioutil.ReadAll(r)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\trat = bytes.NewReader(data)\n\t\tsize = int64(len(data))\n\t}\n\tzr, err := zip.NewReader(rat, size)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfiles := make(map[string]*File)\n\tfor _, file := range zr.File {\n\t\tif file.Mode().IsDir() {\n\t\t\tcontinue\n\t\t}\n\t\tf, err := file.Open()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tdata, err := ioutil.ReadAll(f)\n\t\tf.Close()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tfiles[file.Name] = &File{\n\t\t\tData:    data,\n\t\t\tMode:    file.Mode(),\n\t\t\tModTime: file.ModTime(),\n\t\t}\n\t}\n\treturn Map(files)\n}\n\n// Tar returns an in-memory VFS initialized with the\n// contents of the .tar file read from the given io.Reader.\nfunc Tar(r io.Reader) (VFS, error) {\n\tfiles := make(map[string]*File)\n\ttr := tar.NewReader(r)\n\tfor {\n\t\thdr, err := tr.Next()\n\t\tif err != nil {\n\t\t\tif err == io.EOF {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\treturn nil, err\n\t\t}\n\t\tif hdr.FileInfo().IsDir() {\n\t\t\tcontinue\n\t\t}\n\t\tdata, err := ioutil.ReadAll(tr)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tfiles[hdr.Name] = &File{\n\t\t\tData:    data,\n\t\t\tMode:    hdr.FileInfo().Mode(),\n\t\t\tModTime: hdr.ModTime,\n\t\t}\n\t}\n\treturn Map(files)\n}\n\n// TarGzip returns an in-memory VFS initialized with the\n// contents of the .tar.gz file read from the given io.Reader.\nfunc TarGzip(r io.Reader) (VFS, error) {\n\tzr, err := gzip.NewReader(r)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer zr.Close()\n\treturn Tar(zr)\n}\n\n// TarBzip2 returns an in-memory VFS initialized with the\n// contents of then .tar.bz2 file read from the given io.Reader.\nfunc TarBzip2(r io.Reader) (VFS, error) {\n\tbzr := bzip2.NewReader(r)\n\treturn Tar(bzr)\n}\n\n// Open returns an in-memory VFS initialized with the contents\n// of the given filename, which must have one of the following\n// extensions:\n//\n//  - .zip\n//  - .tar\n//  - .tar.gz\n//  - .tar.bz2\nfunc Open(filename string) (VFS, error) {\n\tf, err := os.Open(filename)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer f.Close()\n\tbase := filepath.Base(filename)\n\text := strings.ToLower(filepath.Ext(base))\n\tnonExt := filename[:len(filename)-len(ext)]\n\tif strings.ToLower(filepath.Ext(nonExt)) == \".tar\" {\n\t\text = \".tar\" + ext\n\t}\n\tswitch ext {\n\tcase \".zip\":\n\t\tst, err := f.Stat()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn Zip(f, st.Size())\n\tcase \".tar\":\n\t\treturn Tar(f)\n\tcase \".tar.gz\":\n\t\treturn TarGzip(f)\n\tcase \".tar.bz2\":\n\t\treturn TarBzip2(f)\n\t}\n\treturn nil, fmt.Errorf(\"can't open a VFS from a %s file\", ext)\n}\n"
  },
  {
    "path": "vendor/github.com/rainycape/vfs/open_test.go",
    "content": "package vfs\n\nimport (\n\t\"path/filepath\"\n\t\"testing\"\n)\n\nfunc testOpenedVFS(t *testing.T, fs VFS) {\n\tdata1, err := ReadFile(fs, \"a/b/c/d\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif string(data1) != \"go\" {\n\t\tt.Errorf(\"expecting a/b/c/d to contain \\\"go\\\", it contains %q instead\", string(data1))\n\t}\n\tdata2, err := ReadFile(fs, \"empty\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif len(data2) > 0 {\n\t\tt.Error(\"non-empty empty file\")\n\t}\n}\n\nfunc testOpenFilename(t *testing.T, filename string) {\n\tp := filepath.Join(\"testdata\", filename)\n\tfs, err := Open(p)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\ttestOpenedVFS(t, fs)\n}\n\nfunc TestOpenZip(t *testing.T) {\n\ttestOpenFilename(t, \"fs.zip\")\n}\n\nfunc TestOpenTar(t *testing.T) {\n\ttestOpenFilename(t, \"fs.tar\")\n}\n\nfunc TestOpenTarGzip(t *testing.T) {\n\ttestOpenFilename(t, \"fs.tar.gz\")\n}\n\nfunc TestOpenTarBzip2(t *testing.T) {\n\ttestOpenFilename(t, \"fs.tar.bz2\")\n}\n"
  },
  {
    "path": "vendor/github.com/rainycape/vfs/rewriter.go",
    "content": "package vfs\n\nimport (\n\t\"fmt\"\n\t\"os\"\n)\n\ntype rewriterFileSystem struct {\n\tfs       VFS\n\trewriter func(string) string\n}\n\nfunc (fs *rewriterFileSystem) VFS() VFS {\n\treturn fs.fs\n}\n\nfunc (fs *rewriterFileSystem) Open(path string) (RFile, error) {\n\treturn fs.fs.Open(fs.rewriter(path))\n}\n\nfunc (fs *rewriterFileSystem) OpenFile(path string, flag int, perm os.FileMode) (WFile, error) {\n\treturn fs.fs.OpenFile(fs.rewriter(path), flag, perm)\n}\n\nfunc (fs *rewriterFileSystem) Lstat(path string) (os.FileInfo, error) {\n\treturn fs.fs.Lstat(fs.rewriter(path))\n}\n\nfunc (fs *rewriterFileSystem) Stat(path string) (os.FileInfo, error) {\n\treturn fs.fs.Stat(fs.rewriter(path))\n}\n\nfunc (fs *rewriterFileSystem) ReadDir(path string) ([]os.FileInfo, error) {\n\treturn fs.fs.ReadDir(fs.rewriter(path))\n}\n\nfunc (fs *rewriterFileSystem) Mkdir(path string, perm os.FileMode) error {\n\treturn fs.fs.Mkdir(fs.rewriter(path), perm)\n}\n\nfunc (fs *rewriterFileSystem) Remove(path string) error {\n\treturn fs.fs.Remove(fs.rewriter(path))\n}\n\nfunc (fs *rewriterFileSystem) String() string {\n\treturn fmt.Sprintf(\"Rewriter %s\", fs.fs.String())\n}\n\n// Rewriter returns a file system which uses the provided function\n// to rewrite paths.\nfunc Rewriter(fs VFS, rewriter func(oldPath string) (newPath string)) VFS {\n\tif rewriter == nil {\n\t\treturn fs\n\t}\n\treturn &rewriterFileSystem{fs: fs, rewriter: rewriter}\n}\n"
  },
  {
    "path": "vendor/github.com/rainycape/vfs/ro.go",
    "content": "package vfs\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n)\n\nvar (\n\t// ErrReadOnlyFileSystem is the error returned by read only file systems\n\t// from calls which would result in a write operation.\n\tErrReadOnlyFileSystem = errors.New(\"read-only filesystem\")\n)\n\ntype readOnlyFileSystem struct {\n\tfs VFS\n}\n\nfunc (fs *readOnlyFileSystem) VFS() VFS {\n\treturn fs.fs\n}\n\nfunc (fs *readOnlyFileSystem) Open(path string) (RFile, error) {\n\treturn fs.fs.Open(path)\n}\n\nfunc (fs *readOnlyFileSystem) OpenFile(path string, flag int, perm os.FileMode) (WFile, error) {\n\tif flag&(os.O_CREATE|os.O_WRONLY|os.O_RDWR) != 0 {\n\t\treturn nil, ErrReadOnlyFileSystem\n\t}\n\treturn fs.fs.OpenFile(path, flag, perm)\n}\n\nfunc (fs *readOnlyFileSystem) Lstat(path string) (os.FileInfo, error) {\n\treturn fs.fs.Lstat(path)\n}\n\nfunc (fs *readOnlyFileSystem) Stat(path string) (os.FileInfo, error) {\n\treturn fs.fs.Stat(path)\n}\n\nfunc (fs *readOnlyFileSystem) ReadDir(path string) ([]os.FileInfo, error) {\n\treturn fs.fs.ReadDir(path)\n}\n\nfunc (fs *readOnlyFileSystem) Mkdir(path string, perm os.FileMode) error {\n\treturn ErrReadOnlyFileSystem\n}\n\nfunc (fs *readOnlyFileSystem) Remove(path string) error {\n\treturn ErrReadOnlyFileSystem\n}\n\nfunc (fs *readOnlyFileSystem) String() string {\n\treturn fmt.Sprintf(\"RO %s\", fs.fs.String())\n}\n\n// ReadOnly returns a read-only filesystem wrapping the given fs.\nfunc ReadOnly(fs VFS) VFS {\n\treturn &readOnlyFileSystem{fs: fs}\n}\n"
  },
  {
    "path": "vendor/github.com/rainycape/vfs/testdata/download-data.sh",
    "content": "#!/bin/sh\n\nSRC=https://storage.googleapis.com/golang/go1.3.src.tar.gz\nif which curl > /dev/null 2>&1; then\n    curl -O ${SRC}\nelif which wget > /dev/null 2&1; then\n    wget -O `basename ${SRC}` ${SRC}\nelse\n    echo \"no curl nor wget found\" 1>&2\n    exit 1\nfi\n"
  },
  {
    "path": "vendor/github.com/rainycape/vfs/testdata/fs/a/b/c/d",
    "content": "go"
  },
  {
    "path": "vendor/github.com/rainycape/vfs/testdata/fs/empty",
    "content": ""
  },
  {
    "path": "vendor/github.com/rainycape/vfs/testdata/update-fs.sh",
    "content": "#!/bin/sh\n\nset -e\ncd fs\nzip -r ../fs.zip *\ntar cvvf ../fs.tar *\ntar cvvzf ../fs.tar.gz *\ntar cvvjf ../fs.tar.bz2 *\ncd -\n"
  },
  {
    "path": "vendor/github.com/rainycape/vfs/util.go",
    "content": "package vfs\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"os\"\n\tpathpkg \"path\"\n\t\"strings\"\n)\n\nvar (\n\t// SkipDir is used by a WalkFunc to signal Walk that\n\t// it wans to skip the given directory.\n\tSkipDir = errors.New(\"skip this directory\")\n\t// ErrReadOnly is returned from Write() on a read-only file.\n\tErrReadOnly = errors.New(\"can't write to read only file\")\n\t// ErrWriteOnly is returned from Read() on a write-only file.\n\tErrWriteOnly = errors.New(\"can't read from write only file\")\n)\n\n// WalkFunc is the function type used by Walk to iterate over a VFS.\ntype WalkFunc func(fs VFS, path string, info os.FileInfo, err error) error\n\nfunc walk(fs VFS, p string, info os.FileInfo, fn WalkFunc) error {\n\terr := fn(fs, p, info, nil)\n\tif err != nil {\n\t\tif info.IsDir() && err == SkipDir {\n\t\t\terr = nil\n\t\t}\n\t\treturn err\n\t}\n\tif !info.IsDir() {\n\t\treturn nil\n\t}\n\tinfos, err := fs.ReadDir(p)\n\tif err != nil {\n\t\treturn fn(fs, p, info, err)\n\t}\n\tfor _, v := range infos {\n\t\tname := pathpkg.Join(p, v.Name())\n\t\tfileInfo, err := fs.Lstat(name)\n\t\tif err != nil {\n\t\t\tif err := fn(fs, name, fileInfo, err); err != nil && err != SkipDir {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tif err := walk(fs, name, fileInfo, fn); err != nil && (!fileInfo.IsDir() || err != SkipDir) {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// Walk iterates over all the files in the VFS which descend from the given\n// root (including root itself), descending into any subdirectories. In each\n// directory, files are visited in alphabetical order. The given function might\n// chose to skip a directory by returning SkipDir.\nfunc Walk(fs VFS, root string, fn WalkFunc) error {\n\tinfo, err := fs.Lstat(root)\n\tif err != nil {\n\t\treturn fn(fs, root, nil, err)\n\t}\n\treturn walk(fs, root, info, fn)\n}\n\nfunc makeDir(fs VFS, path string, perm os.FileMode) error {\n\tstat, err := fs.Lstat(path)\n\tif err == nil {\n\t\tif !stat.IsDir() {\n\t\t\treturn fmt.Errorf(\"%s exists and is not a directory\", path)\n\t\t}\n\t} else {\n\t\tif err := fs.Mkdir(path, perm); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// MkdirAll makes all directories pointed by the given path, using the same\n// permissions for all of them. Note that MkdirAll skips directories which\n// already exists rather than returning an error.\nfunc MkdirAll(fs VFS, path string, perm os.FileMode) error {\n\tcur := \"/\"\n\tif err := makeDir(fs, cur, perm); err != nil {\n\t\treturn err\n\t}\n\tparts := strings.Split(path, \"/\")\n\tfor _, v := range parts {\n\t\tcur += v\n\t\tif err := makeDir(fs, cur, perm); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tcur += \"/\"\n\t}\n\treturn nil\n}\n\n// RemoveAll removes all files from the given fs and path, including\n// directories (by removing its contents first).\nfunc RemoveAll(fs VFS, path string) error {\n\tstat, err := fs.Lstat(path)\n\tif err != nil {\n\t\tif err == os.ErrNotExist {\n\t\t\treturn nil\n\t\t}\n\t\treturn err\n\t}\n\tif stat.IsDir() {\n\t\tfiles, err := fs.ReadDir(path)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tfor _, v := range files {\n\t\t\tfilePath := pathpkg.Join(path, v.Name())\n\t\t\tif err := RemoveAll(fs, filePath); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\treturn fs.Remove(path)\n}\n\n// ReadFile reads the file at the given path from the given fs, returning\n// either its contents or an error if the file couldn't be read.\nfunc ReadFile(fs VFS, path string) ([]byte, error) {\n\tf, err := fs.Open(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer f.Close()\n\treturn ioutil.ReadAll(f)\n}\n\n// WriteFile writes a file at the given path and fs with the given data and\n// permissions. If the file already exists, WriteFile truncates it before\n// writing. If the file can't be created, an error will be returned.\nfunc WriteFile(fs VFS, path string, data []byte, perm os.FileMode) error {\n\tf, err := fs.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, perm)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif _, err := f.Write(data); err != nil {\n\t\tf.Close()\n\t\treturn err\n\t}\n\treturn f.Close()\n}\n\n// Clone copies all the files from the src VFS to dst. Note that files or directories with\n// all permissions set to 0 will be set to 0755 for directories and 0644 for files. If you\n// need more granularity, use Walk directly to clone the file systems.\nfunc Clone(dst VFS, src VFS) error {\n\terr := Walk(src, \"/\", func(fs VFS, path string, info os.FileInfo, err error) error {\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif info.IsDir() {\n\t\t\tperm := info.Mode() & os.ModePerm\n\t\t\tif perm == 0 {\n\t\t\t\tperm = 0755\n\t\t\t}\n\t\t\terr := dst.Mkdir(path, info.Mode()|perm)\n\t\t\tif err != nil && !IsExist(err) {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\treturn nil\n\t\t}\n\t\tdata, err := ReadFile(fs, path)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tperm := info.Mode() & os.ModePerm\n\t\tif perm == 0 {\n\t\t\tperm = 0644\n\t\t}\n\t\tif err := WriteFile(dst, path, data, info.Mode()|perm); err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n\treturn err\n}\n\n// IsExist returns wheter the error indicates that the file or directory\n// already exists.\nfunc IsExist(err error) bool {\n\treturn os.IsExist(err)\n}\n\n// IsExist returns wheter the error indicates that the file or directory\n// does not exist.\nfunc IsNotExist(err error) bool {\n\treturn os.IsNotExist(err)\n}\n\n// Compressor is the interface implemented by VFS files which can be\n// transparently compressed and decompressed. Currently, this is only\n// supported by the in-memory filesystems.\ntype Compressor interface {\n\tIsCompressed() bool\n\tSetCompressed(c bool)\n}\n\n// Compress is a shorthand method for compressing all the files in a VFS.\n// Note that not all file systems support transparent compression/decompression.\nfunc Compress(fs VFS) error {\n\treturn Walk(fs, \"/\", func(fs VFS, p string, info os.FileInfo, err error) error {\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tmode := info.Mode()\n\t\tif mode.IsDir() || mode&ModeCompress != 0 {\n\t\t\treturn nil\n\t\t}\n\t\tf, err := fs.Open(p)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif c, ok := f.(Compressor); ok {\n\t\t\tc.SetCompressed(true)\n\t\t}\n\t\treturn f.Close()\n\t})\n}\n"
  },
  {
    "path": "vendor/github.com/rainycape/vfs/vfs.go",
    "content": "package vfs\n\nimport (\n\t\"io\"\n\t\"os\"\n)\n\n// Opener is the interface which specifies the methods for\n// opening a file. All the VFS implementations implement\n// this interface.\ntype Opener interface {\n\t// Open returns a readable file at the given path. See also\n\t// the shorthand function ReadFile.\n\tOpen(path string) (RFile, error)\n\t// OpenFile returns a readable and writable file at the given\n\t// path. Note that, depending on the flags, the file might be\n\t// only readable or only writable. See also the shorthand\n\t// function WriteFile.\n\tOpenFile(path string, flag int, perm os.FileMode) (WFile, error)\n}\n\n// RFile is the interface implemented by the returned value from a VFS\n// Open method. It allows reading and seeking, and must be closed after use.\ntype RFile interface {\n\tio.Reader\n\tio.Seeker\n\tio.Closer\n}\n\n// WFile is the interface implemented by the returned value from a VFS\n// OpenFile method. It allows reading, seeking and writing, and must\n// be closed after use. Note that, depending on the flags passed to\n// OpenFile, the Read or Write methods might always return an error (e.g.\n// if the file was opened in read-only or write-only mode).\ntype WFile interface {\n\tio.Reader\n\tio.Writer\n\tio.Seeker\n\tio.Closer\n}\n\n// VFS is the interface implemented by all the Virtual File Systems.\ntype VFS interface {\n\tOpener\n\t// Lstat returns the os.FileInfo for the given path, without\n\t// following symlinks.\n\tLstat(path string) (os.FileInfo, error)\n\t// Stat returns the os.FileInfo for the given path, following\n\t// symlinks.\n\tStat(path string) (os.FileInfo, error)\n\t// ReadDir returns the contents of the directory at path as an slice\n\t// of os.FileInfo, ordered alphabetically by name. If path is not a\n\t// directory or the permissions don't allow it, an error will be\n\t// returned.\n\tReadDir(path string) ([]os.FileInfo, error)\n\t// Mkdir creates a directory at the given path. If the directory\n\t// already exists or its parent directory does not exist or\n\t// the permissions don't allow it, an error will be returned. See\n\t// also the shorthand function MkdirAll.\n\tMkdir(path string, perm os.FileMode) error\n\t// Remove removes the item at the given path. If the path does\n\t// not exists or the permissions don't allow removing it or it's\n\t// a non-empty directory, an error will be returned. See also\n\t// the shorthand function RemoveAll.\n\tRemove(path string) error\n\t// String returns a human-readable description of the VFS.\n\tString() string\n}\n\n// TemporaryVFS represents a temporary on-disk file system which can be removed\n// by calling its Close method.\ntype TemporaryVFS interface {\n\tVFS\n\t// Root returns the root directory for the temporary VFS.\n\tRoot() string\n\t// Close removes all the files in temporary VFS.\n\tClose() error\n}\n\n// Container is implemented by some file systems which\n// contain another one.\ntype Container interface {\n\t// VFS returns the underlying VFS.\n\tVFS() VFS\n}\n"
  },
  {
    "path": "vendor/github.com/rainycape/vfs/vfs_test.go",
    "content": "package vfs\n\nimport (\n\t\"crypto/sha1\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"reflect\"\n\t\"testing\"\n)\n\nconst (\n\tgoTestFile = \"go1.3.src.tar.gz\"\n)\n\ntype errNoTestFile string\n\nfunc (e errNoTestFile) Error() string {\n\treturn fmt.Sprintf(\"%s test file not found, use testdata/download-data.sh to fetch it\", filepath.Base(string(e)))\n}\n\nfunc openOptionalTestFile(t testing.TB, name string) *os.File {\n\tfilename := filepath.Join(\"testdata\", name)\n\tf, err := os.Open(filename)\n\tif err != nil {\n\t\tt.Skip(errNoTestFile(filename))\n\t}\n\treturn f\n}\n\nfunc testVFS(t *testing.T, fs VFS) {\n\tif err := WriteFile(fs, \"a\", []byte(\"A\"), 0644); err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdata, err := ReadFile(fs, \"a\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif string(data) != \"A\" {\n\t\tt.Errorf(\"expecting file a to contain \\\"A\\\" got %q instead\", string(data))\n\t}\n\tif err := WriteFile(fs, \"b\", []byte(\"B\"), 0755); err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif _, err := fs.OpenFile(\"b\", os.O_CREATE|os.O_TRUNC|os.O_EXCL|os.O_WRONLY, 0755); err == nil || !IsExist(err) {\n\t\tt.Errorf(\"error should be ErrExist, it's %v\", err)\n\t}\n\tfb, err := fs.OpenFile(\"b\", os.O_TRUNC|os.O_WRONLY, 0755)\n\tif err != nil {\n\t\tt.Fatalf(\"error opening b: %s\", err)\n\t}\n\tif _, err := fb.Write([]byte(\"BB\")); err != nil {\n\t\tt.Errorf(\"error writing to b: %s\", err)\n\t}\n\tif _, err := fb.Seek(0, os.SEEK_SET); err != nil {\n\t\tt.Errorf(\"error seeking b: %s\", err)\n\t}\n\tif _, err := fb.Read(make([]byte, 2)); err == nil {\n\t\tt.Error(\"allowed reading WRONLY file b\")\n\t}\n\tif err := fb.Close(); err != nil {\n\t\tt.Errorf(\"error closing b: %s\", err)\n\t}\n\tfiles, err := fs.ReadDir(\"/\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif len(files) != 2 {\n\t\tt.Errorf(\"expecting 2 files, got %d\", len(files))\n\t}\n\tif n := files[0].Name(); n != \"a\" {\n\t\tt.Errorf(\"expecting first file named \\\"a\\\", got %q\", n)\n\t}\n\tif n := files[1].Name(); n != \"b\" {\n\t\tt.Errorf(\"expecting first file named \\\"b\\\", got %q\", n)\n\t}\n\tfor ii, v := range files {\n\t\tes := int64(ii + 1)\n\t\tif s := v.Size(); es != s {\n\t\t\tt.Errorf(\"expecting file %s to have size %d, has %d\", v.Name(), es, s)\n\t\t}\n\t}\n\tif err := MkdirAll(fs, \"a/b/c/d\", 0); err == nil {\n\t\tt.Error(\"should not allow dir over file\")\n\t}\n\tif err := MkdirAll(fs, \"c/d\", 0755); err != nil {\n\t\tt.Fatal(err)\n\t}\n\t// Idempotent\n\tif err := MkdirAll(fs, \"c/d\", 0755); err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif err := fs.Mkdir(\"c\", 0755); err == nil || !IsExist(err) {\n\t\tt.Errorf(\"err should be ErrExist, it's %v\", err)\n\t}\n\t// Should fail to remove, c is not empty\n\tif err := fs.Remove(\"c\"); err == nil {\n\t\tt.Fatalf(\"removed non-empty directory\")\n\t}\n\tvar walked []os.FileInfo\n\tvar walkedNames []string\n\terr = Walk(fs, \"c\", func(fs VFS, path string, info os.FileInfo, err error) error {\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\twalked = append(walked, info)\n\t\twalkedNames = append(walkedNames, path)\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif exp := []string{\"c\", \"c/d\"}; !reflect.DeepEqual(exp, walkedNames) {\n\t\tt.Error(\"expecting walked names %v, got %v\", exp, walkedNames)\n\t}\n\tfor _, v := range walked {\n\t\tif !v.IsDir() {\n\t\t\tt.Errorf(\"%s should be a dir\", v.Name())\n\t\t}\n\t}\n\tif err := RemoveAll(fs, \"c\"); err != nil {\n\t\tt.Fatal(err)\n\t}\n\terr = Walk(fs, \"c\", func(fs VFS, path string, info os.FileInfo, err error) error {\n\t\treturn err\n\t})\n\tif err == nil || !IsNotExist(err) {\n\t\tt.Errorf(\"error should be ErrNotExist, it's %v\", err)\n\t}\n}\n\nfunc TestMapFS(t *testing.T) {\n\tfs, err := Map(nil)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\ttestVFS(t, fs)\n}\n\nfunc TestPopulatedMap(t *testing.T) {\n\tfiles := map[string]*File{\n\t\t\"a/1\": &File{},\n\t\t\"a/2\": &File{},\n\t}\n\tfs, err := Map(files)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tinfos, err := fs.ReadDir(\"a\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif c := len(infos); c != 2 {\n\t\tt.Fatalf(\"expecting 2 files in a, got %d\", c)\n\t}\n\tif infos[0].Name() != \"1\" || infos[1].Name() != \"2\" {\n\t\tt.Errorf(\"expecting names 1, 2 got %q, %q\", infos[0].Name(), infos[1].Name())\n\t}\n}\n\nfunc TestBadPopulatedMap(t *testing.T) {\n\t// 1 can't be file and directory\n\tfiles := map[string]*File{\n\t\t\"a/1\":   &File{},\n\t\t\"a/1/2\": &File{},\n\t}\n\t_, err := Map(files)\n\tif err == nil {\n\t\tt.Fatal(\"Map should not work with a path as both file and directory\")\n\t}\n}\n\nfunc TestTmpFS(t *testing.T) {\n\tfs, err := TmpFS(\"vfs-test\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer fs.Close()\n\ttestVFS(t, fs)\n}\n\nconst (\n\tgo13FileCount = 4157\n\t// +1 because of the root, the real count is 407\n\tgo13DirCount = 407 + 1\n)\n\nfunc countFileSystem(fs VFS) (int, int, error) {\n\tfiles, dirs := 0, 0\n\terr := Walk(fs, \"/\", func(fs VFS, _ string, info os.FileInfo, err error) error {\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif info.IsDir() {\n\t\t\tdirs++\n\t\t} else {\n\t\t\tfiles++\n\t\t}\n\t\treturn nil\n\t})\n\treturn files, dirs, err\n}\n\nfunc testGoFileCount(t *testing.T, fs VFS) {\n\tfiles, dirs, err := countFileSystem(fs)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif files != go13FileCount {\n\t\tt.Errorf(\"expecting %d files in go1.3, got %d instead\", go13FileCount, files)\n\t}\n\tif dirs != go13DirCount {\n\t\tt.Errorf(\"expecting %d directories in go1.3, got %d instead\", go13DirCount, dirs)\n\t}\n}\n\nfunc TestGo13Files(t *testing.T) {\n\tf := openOptionalTestFile(t, goTestFile)\n\tdefer f.Close()\n\tfs, err := TarGzip(f)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\ttestGoFileCount(t, fs)\n}\n\nfunc TestMounter(t *testing.T) {\n\tm := &Mounter{}\n\tf := openOptionalTestFile(t, goTestFile)\n\tdefer f.Close()\n\tfs, err := TarGzip(f)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tm.Mount(fs, \"/\")\n\ttestGoFileCount(t, m)\n}\n\nfunc TestClone(t *testing.T) {\n\tfs, err := Open(filepath.Join(\"testdata\", \"fs.zip\"))\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tinfos1, err := fs.ReadDir(\"/\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tmem1 := Memory()\n\tif err := Clone(mem1, fs); err != nil {\n\t\tt.Fatal(err)\n\t}\n\tinfos2, err := mem1.ReadDir(\"/\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif len(infos2) != len(infos1) {\n\t\tt.Fatalf(\"cloned fs has %d entries in / rather than %d\", len(infos2), len(infos1))\n\t}\n\tmem2 := Memory()\n\tif err := Clone(mem2, mem1); err != nil {\n\t\tt.Fatal(err)\n\t}\n\tinfos3, err := mem2.ReadDir(\"/\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif len(infos3) != len(infos2) {\n\t\tt.Fatalf(\"cloned fs has %d entries in / rather than %d\", len(infos3), len(infos2))\n\t}\n}\n\nfunc measureVFSMemorySize(t testing.TB, fs VFS) int {\n\tmem, ok := fs.(*memoryFileSystem)\n\tif !ok {\n\t\tt.Fatalf(\"%T is not a memory filesystem\", fs)\n\t}\n\tvar total int\n\tvar f func(d *Dir)\n\tf = func(d *Dir) {\n\t\tfor _, v := range d.Entries {\n\t\t\ttotal += int(v.Size())\n\t\t\tif sd, ok := v.(*Dir); ok {\n\t\t\t\tf(sd)\n\t\t\t}\n\t\t}\n\t}\n\tf(mem.root)\n\treturn total\n}\n\nfunc hashVFS(t testing.TB, fs VFS) string {\n\tsha := sha1.New()\n\terr := Walk(fs, \"/\", func(fs VFS, p string, info os.FileInfo, err error) error {\n\t\tif err != nil || info.IsDir() {\n\t\t\treturn err\n\t\t}\n\t\tf, err := fs.Open(p)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tdefer f.Close()\n\t\tif _, err := io.Copy(sha, f); err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\treturn hex.EncodeToString(sha.Sum(nil))\n}\n\nfunc TestCompress(t *testing.T) {\n\tf := openOptionalTestFile(t, goTestFile)\n\tdefer f.Close()\n\tfs, err := TarGzip(f)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tsize1 := measureVFSMemorySize(t, fs)\n\thash1 := hashVFS(t, fs)\n\tif err := Compress(fs); err != nil {\n\t\tt.Fatalf(\"can't compress fs: %s\", err)\n\t}\n\ttestGoFileCount(t, fs)\n\tsize2 := measureVFSMemorySize(t, fs)\n\thash2 := hashVFS(t, fs)\n\tif size2 >= size1 {\n\t\tt.Fatalf(\"compressed fs takes more memory %d than bare fs %d\", size2, size1)\n\t}\n\tif hash1 != hash2 {\n\t\tt.Fatalf(\"compressing fs changed hash from %s to %s\", hash1, hash2)\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/rainycape/vfs/write.go",
    "content": "package vfs\n\nimport (\n\t\"archive/tar\"\n\t\"archive/zip\"\n\t\"compress/gzip\"\n\t\"io\"\n\t\"os\"\n)\n\nfunc copyVFS(fs VFS, copier func(p string, info os.FileInfo, f io.Reader) error) error {\n\treturn Walk(fs, \"/\", func(vfs VFS, p string, info os.FileInfo, err error) error {\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif info.IsDir() {\n\t\t\treturn nil\n\t\t}\n\t\tf, err := fs.Open(p)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tdefer f.Close()\n\t\treturn copier(p[1:], info, f)\n\t})\n}\n\n// WriteZip writes the given VFS as a zip file to the given io.Writer.\nfunc WriteZip(w io.Writer, fs VFS) error {\n\tzw := zip.NewWriter(w)\n\terr := copyVFS(fs, func(p string, info os.FileInfo, f io.Reader) error {\n\t\thdr, err := zip.FileInfoHeader(info)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\thdr.Name = p\n\t\tfw, err := zw.CreateHeader(hdr)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\t_, err = io.Copy(fw, f)\n\t\treturn err\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn zw.Close()\n}\n\n// WriteTar writes the given VFS as a tar file to the given io.Writer.\nfunc WriteTar(w io.Writer, fs VFS) error {\n\ttw := tar.NewWriter(w)\n\terr := copyVFS(fs, func(p string, info os.FileInfo, f io.Reader) error {\n\t\thdr, err := tar.FileInfoHeader(info, \"\")\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\thdr.Name = p\n\t\tif err := tw.WriteHeader(hdr); err != nil {\n\t\t\treturn err\n\t\t}\n\t\t_, err = io.Copy(tw, f)\n\t\treturn err\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn tw.Close()\n}\n\n// WriteTarGzip writes the given VFS as a tar.gz file to the given io.Writer.\nfunc WriteTarGzip(w io.Writer, fs VFS) error {\n\tgw, err := gzip.NewWriterLevel(w, gzip.BestCompression)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif err := WriteTar(gw, fs); err != nil {\n\t\treturn err\n\t}\n\treturn gw.Close()\n}\n"
  },
  {
    "path": "vendor/github.com/rainycape/vfs/write_test.go",
    "content": "package vfs\n\nimport (\n\t\"bytes\"\n\t\"io\"\n\t\"path/filepath\"\n\t\"testing\"\n)\n\ntype writeTester struct {\n\tname   string\n\twriter func(io.Writer, VFS) error\n\treader func(io.Reader) (VFS, error)\n}\n\nfunc TestWrite(t *testing.T) {\n\tvar (\n\t\twriteTests = []writeTester{\n\t\t\t{\"zip\", WriteZip, func(r io.Reader) (VFS, error) { return Zip(r, 0) }},\n\t\t\t{\"tar\", WriteTar, Tar},\n\t\t\t{\"tar.gz\", WriteTarGzip, TarGzip},\n\t\t}\n\t)\n\tp := filepath.Join(\"testdata\", \"fs.zip\")\n\tfs, err := Open(p)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tvar buf bytes.Buffer\n\tfor _, v := range writeTests {\n\t\tbuf.Reset()\n\t\tif err := v.writer(&buf, fs); err != nil {\n\t\t\tt.Fatalf(\"error writing %s: %s\", v.name, err)\n\t\t}\n\t\tnewFs, err := v.reader(&buf)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"error reading %s: %s\", v.name, err)\n\t\t}\n\t\ttestOpenedVFS(t, newFs)\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/stretchr/testify/assert/assertions.go",
    "content": "package assert\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"regexp\"\n\t\"runtime\"\n\t\"strings\"\n\t\"time\"\n)\n\n// TestingT is an interface wrapper around *testing.T\ntype TestingT interface {\n\tErrorf(format string, args ...interface{})\n}\n\n// Comparison a custom function that returns true on success and false on failure\ntype Comparison func() (success bool)\n\n/*\n\tHelper functions\n*/\n\n// ObjectsAreEqual determines if two objects are considered equal.\n//\n// This function does no assertion of any kind.\nfunc ObjectsAreEqual(expected, actual interface{}) bool {\n\n\tif expected == nil || actual == nil {\n\t\treturn expected == actual\n\t}\n\n\tif reflect.DeepEqual(expected, actual) {\n\t\treturn true\n\t}\n\n\texpectedValue := reflect.ValueOf(expected)\n\tactualValue := reflect.ValueOf(actual)\n\tif expectedValue == actualValue {\n\t\treturn true\n\t}\n\n\t// Attempt comparison after type conversion\n\tif actualValue.Type().ConvertibleTo(expectedValue.Type()) && expectedValue == actualValue.Convert(expectedValue.Type()) {\n\t\treturn true\n\t}\n\n\t// Last ditch effort\n\tif fmt.Sprintf(\"%#v\", expected) == fmt.Sprintf(\"%#v\", actual) {\n\t\treturn true\n\t}\n\n\treturn false\n\n}\n\n/* CallerInfo is necessary because the assert functions use the testing object\ninternally, causing it to print the file:line of the assert method, rather than where\nthe problem actually occured in calling code.*/\n\n// CallerInfo returns a string containing the file and line number of the assert call\n// that failed.\nfunc CallerInfo() string {\n\n\tfile := \"\"\n\tline := 0\n\tok := false\n\n\tfor i := 0; ; i++ {\n\t\t_, file, line, ok = runtime.Caller(i)\n\t\tif !ok {\n\t\t\treturn \"\"\n\t\t}\n\t\tparts := strings.Split(file, \"/\")\n\t\tdir := parts[len(parts)-2]\n\t\tfile = parts[len(parts)-1]\n\t\tif (dir != \"assert\" && dir != \"mock\" && dir != \"require\") || file == \"mock_test.go\" {\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn fmt.Sprintf(\"%s:%d\", file, line)\n}\n\n// getWhitespaceString returns a string that is long enough to overwrite the default\n// output from the go testing framework.\nfunc getWhitespaceString() string {\n\n\t_, file, line, ok := runtime.Caller(1)\n\tif !ok {\n\t\treturn \"\"\n\t}\n\tparts := strings.Split(file, \"/\")\n\tfile = parts[len(parts)-1]\n\n\treturn strings.Repeat(\" \", len(fmt.Sprintf(\"%s:%d:      \", file, line)))\n\n}\n\nfunc messageFromMsgAndArgs(msgAndArgs ...interface{}) string {\n\tif len(msgAndArgs) == 0 || msgAndArgs == nil {\n\t\treturn \"\"\n\t}\n\tif len(msgAndArgs) == 1 {\n\t\treturn msgAndArgs[0].(string)\n\t}\n\tif len(msgAndArgs) > 1 {\n\t\treturn fmt.Sprintf(msgAndArgs[0].(string), msgAndArgs[1:]...)\n\t}\n\treturn \"\"\n}\n\n// Indents all lines of the message by appending a number of tabs to each line, in an output format compatible with Go's\n// test printing (see inner comment for specifics)\nfunc indentMessageLines(message string, tabs int) string {\n\toutBuf := new(bytes.Buffer)\n\n\tfor i, scanner := 0, bufio.NewScanner(strings.NewReader(message)); scanner.Scan(); i++ {\n\t\tif i != 0 {\n\t\t\toutBuf.WriteRune('\\n')\n\t\t}\n\t\tfor ii := 0; ii < tabs; ii++ {\n\t\t\toutBuf.WriteRune('\\t')\n\t\t\t// Bizarrely, all lines except the first need one fewer tabs prepended, so deliberately advance the counter\n\t\t\t// by 1 prematurely.\n\t\t\tif ii == 0 && i > 0 {\n\t\t\t\tii++\n\t\t\t}\n\t\t}\n\t\toutBuf.WriteString(scanner.Text())\n\t}\n\n\treturn outBuf.String()\n}\n\n// Fail reports a failure through\nfunc Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool {\n\n\tmessage := messageFromMsgAndArgs(msgAndArgs...)\n\n\tif len(message) > 0 {\n\t\tt.Errorf(\"\\r%s\\r\\tLocation:\\t%s\\n\"+\n\t\t\t\"\\r\\tError:%s\\n\"+\n\t\t\t\"\\r\\tMessages:\\t%s\\n\\r\",\n\t\t\tgetWhitespaceString(),\n\t\t\tCallerInfo(),\n\t\t\tindentMessageLines(failureMessage, 2),\n\t\t\tmessage)\n\t} else {\n\t\tt.Errorf(\"\\r%s\\r\\tLocation:\\t%s\\n\"+\n\t\t\t\"\\r\\tError:%s\\n\\r\",\n\t\t\tgetWhitespaceString(),\n\t\t\tCallerInfo(),\n\t\t\tindentMessageLines(failureMessage, 2))\n\t}\n\n\treturn false\n}\n\n// Implements asserts that an object is implemented by the specified interface.\n//\n//    assert.Implements(t, (*MyInterface)(nil), new(MyObject), \"MyObject\")\nfunc Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool {\n\n\tinterfaceType := reflect.TypeOf(interfaceObject).Elem()\n\n\tif !reflect.TypeOf(object).Implements(interfaceType) {\n\t\treturn Fail(t, fmt.Sprintf(\"Object must implement %v\", interfaceType), msgAndArgs...)\n\t}\n\n\treturn true\n\n}\n\n// IsType asserts that the specified objects are of the same type.\nfunc IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool {\n\n\tif !ObjectsAreEqual(reflect.TypeOf(object), reflect.TypeOf(expectedType)) {\n\t\treturn Fail(t, fmt.Sprintf(\"Object expected to be of type %v, but was %v\", reflect.TypeOf(expectedType), reflect.TypeOf(object)), msgAndArgs...)\n\t}\n\n\treturn true\n}\n\n// Equal asserts that two objects are equal.\n//\n//    assert.Equal(t, 123, 123, \"123 and 123 should be equal\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {\n\n\tif !ObjectsAreEqual(expected, actual) {\n\t\treturn Fail(t, fmt.Sprintf(\"Not equal: %#v (expected)\\n\"+\n\t\t\t\"        != %#v (actual)\", expected, actual), msgAndArgs...)\n\t}\n\n\treturn true\n\n}\n\n// Exactly asserts that two objects are equal is value and type.\n//\n//    assert.Exactly(t, int32(123), int64(123), \"123 and 123 should NOT be equal\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {\n\n\taType := reflect.TypeOf(expected)\n\tbType := reflect.TypeOf(actual)\n\n\tif aType != bType {\n\t\treturn Fail(t, \"Types expected to match exactly\", \"%v != %v\", aType, bType)\n\t}\n\n\treturn Equal(t, expected, actual, msgAndArgs...)\n\n}\n\n// NotNil asserts that the specified object is not nil.\n//\n//    assert.NotNil(t, err, \"err should be something\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {\n\n\tsuccess := true\n\n\tif object == nil {\n\t\tsuccess = false\n\t} else {\n\t\tvalue := reflect.ValueOf(object)\n\t\tkind := value.Kind()\n\t\tif kind >= reflect.Chan && kind <= reflect.Slice && value.IsNil() {\n\t\t\tsuccess = false\n\t\t}\n\t}\n\n\tif !success {\n\t\tFail(t, \"Expected not to be nil.\", msgAndArgs...)\n\t}\n\n\treturn success\n}\n\n// isNil checks if a specified object is nil or not, without Failing.\nfunc isNil(object interface{}) bool {\n\tif object == nil {\n\t\treturn true\n\t}\n\n\tvalue := reflect.ValueOf(object)\n\tkind := value.Kind()\n\tif kind >= reflect.Chan && kind <= reflect.Slice && value.IsNil() {\n\t\treturn true\n\t}\n\n\treturn false\n}\n\n// Nil asserts that the specified object is nil.\n//\n//    assert.Nil(t, err, \"err should be nothing\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {\n\tif isNil(object) {\n\t\treturn true\n\t}\n\treturn Fail(t, fmt.Sprintf(\"Expected nil, but got: %#v\", object), msgAndArgs...)\n}\n\nvar zeros = []interface{}{\n\tint(0),\n\tint8(0),\n\tint16(0),\n\tint32(0),\n\tint64(0),\n\tuint(0),\n\tuint8(0),\n\tuint16(0),\n\tuint32(0),\n\tuint64(0),\n\tfloat32(0),\n\tfloat64(0),\n}\n\n// isEmpty gets whether the specified object is considered empty or not.\nfunc isEmpty(object interface{}) bool {\n\n\tif object == nil {\n\t\treturn true\n\t} else if object == \"\" {\n\t\treturn true\n\t} else if object == false {\n\t\treturn true\n\t}\n\n\tfor _, v := range zeros {\n\t\tif object == v {\n\t\t\treturn true\n\t\t}\n\t}\n\n\tobjValue := reflect.ValueOf(object)\n\n\tswitch objValue.Kind() {\n\tcase reflect.Map:\n\t\tfallthrough\n\tcase reflect.Slice, reflect.Chan:\n\t\t{\n\t\t\treturn (objValue.Len() == 0)\n\t\t}\n\tcase reflect.Ptr:\n\t\t{\n\t\t\tswitch object.(type) {\n\t\t\tcase *time.Time:\n\t\t\t\treturn object.(*time.Time).IsZero()\n\t\t\tdefault:\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t}\n\treturn false\n}\n\n// Empty asserts that the specified object is empty.  I.e. nil, \"\", false, 0 or either\n// a slice or a channel with len == 0.\n//\n// assert.Empty(t, obj)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {\n\n\tpass := isEmpty(object)\n\tif !pass {\n\t\tFail(t, fmt.Sprintf(\"Should be empty, but was %v\", object), msgAndArgs...)\n\t}\n\n\treturn pass\n\n}\n\n// NotEmpty asserts that the specified object is NOT empty.  I.e. not nil, \"\", false, 0 or either\n// a slice or a channel with len == 0.\n//\n// if assert.NotEmpty(t, obj) {\n//   assert.Equal(t, \"two\", obj[1])\n// }\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {\n\n\tpass := !isEmpty(object)\n\tif !pass {\n\t\tFail(t, fmt.Sprintf(\"Should NOT be empty, but was %v\", object), msgAndArgs...)\n\t}\n\n\treturn pass\n\n}\n\n// getLen try to get length of object.\n// return (false, 0) if impossible.\nfunc getLen(x interface{}) (ok bool, length int) {\n\tv := reflect.ValueOf(x)\n\tdefer func() {\n\t\tif e := recover(); e != nil {\n\t\t\tok = false\n\t\t}\n\t}()\n\treturn true, v.Len()\n}\n\n// Len asserts that the specified object has specific length.\n// Len also fails if the object has a type that len() not accept.\n//\n//    assert.Len(t, mySlice, 3, \"The size of slice is not 3\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) bool {\n\tok, l := getLen(object)\n\tif !ok {\n\t\treturn Fail(t, fmt.Sprintf(\"\\\"%s\\\" could not be applied builtin len()\", object), msgAndArgs...)\n\t}\n\n\tif l != length {\n\t\treturn Fail(t, fmt.Sprintf(\"\\\"%s\\\" should have %d item(s), but has %d\", object, length, l), msgAndArgs...)\n\t}\n\treturn true\n}\n\n// True asserts that the specified value is true.\n//\n//    assert.True(t, myBool, \"myBool should be true\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc True(t TestingT, value bool, msgAndArgs ...interface{}) bool {\n\n\tif value != true {\n\t\treturn Fail(t, \"Should be true\", msgAndArgs...)\n\t}\n\n\treturn true\n\n}\n\n// False asserts that the specified value is true.\n//\n//    assert.False(t, myBool, \"myBool should be false\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc False(t TestingT, value bool, msgAndArgs ...interface{}) bool {\n\n\tif value != false {\n\t\treturn Fail(t, \"Should be false\", msgAndArgs...)\n\t}\n\n\treturn true\n\n}\n\n// NotEqual asserts that the specified values are NOT equal.\n//\n//    assert.NotEqual(t, obj1, obj2, \"two objects shouldn't be equal\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {\n\n\tif ObjectsAreEqual(expected, actual) {\n\t\treturn Fail(t, \"Should not be equal\", msgAndArgs...)\n\t}\n\n\treturn true\n\n}\n\n// containsElement try loop over the list check if the list includes the element.\n// return (false, false) if impossible.\n// return (true, false) if element was not found.\n// return (true, true) if element was found.\nfunc includeElement(list interface{}, element interface{}) (ok, found bool) {\n\n\tlistValue := reflect.ValueOf(list)\n\telementValue := reflect.ValueOf(element)\n\tdefer func() {\n\t\tif e := recover(); e != nil {\n\t\t\tok = false\n\t\t\tfound = false\n\t\t}\n\t}()\n\n\tif reflect.TypeOf(list).Kind() == reflect.String {\n\t\treturn true, strings.Contains(listValue.String(), elementValue.String())\n\t}\n\n\tfor i := 0; i < listValue.Len(); i++ {\n\t\tif listValue.Index(i).Interface() == element {\n\t\t\treturn true, true\n\t\t}\n\t}\n\treturn true, false\n\n}\n\n// Contains asserts that the specified string or list(array, slice...) contains the\n// specified substring or element.\n//\n//    assert.Contains(t, \"Hello World\", \"World\", \"But 'Hello World' does contain 'World'\")\n//    assert.Contains(t, [\"Hello\", \"World\"], \"World\", \"But [\"Hello\", \"World\"] does contain 'World'\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool {\n\n\tok, found := includeElement(s, contains)\n\tif !ok {\n\t\treturn Fail(t, fmt.Sprintf(\"\\\"%s\\\" could not be applied builtin len()\", s), msgAndArgs...)\n\t}\n\tif !found {\n\t\treturn Fail(t, fmt.Sprintf(\"\\\"%s\\\" does not contain \\\"%s\\\"\", s, contains), msgAndArgs...)\n\t}\n\n\treturn true\n\n}\n\n// NotContains asserts that the specified string or list(array, slice...) does NOT contain the\n// specified substring or element.\n//\n//    assert.NotContains(t, \"Hello World\", \"Earth\", \"But 'Hello World' does NOT contain 'Earth'\")\n//    assert.NotContains(t, [\"Hello\", \"World\"], \"Earth\", \"But ['Hello', 'World'] does NOT contain 'Earth'\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool {\n\n\tok, found := includeElement(s, contains)\n\tif !ok {\n\t\treturn Fail(t, fmt.Sprintf(\"\\\"%s\\\" could not be applied builtin len()\", s), msgAndArgs...)\n\t}\n\tif found {\n\t\treturn Fail(t, fmt.Sprintf(\"\\\"%s\\\" should not contain \\\"%s\\\"\", s, contains), msgAndArgs...)\n\t}\n\n\treturn true\n\n}\n\n// Condition uses a Comparison to assert a complex condition.\nfunc Condition(t TestingT, comp Comparison, msgAndArgs ...interface{}) bool {\n\tresult := comp()\n\tif !result {\n\t\tFail(t, \"Condition failed!\", msgAndArgs...)\n\t}\n\treturn result\n}\n\n// PanicTestFunc defines a func that should be passed to the assert.Panics and assert.NotPanics\n// methods, and represents a simple func that takes no arguments, and returns nothing.\ntype PanicTestFunc func()\n\n// didPanic returns true if the function passed to it panics. Otherwise, it returns false.\nfunc didPanic(f PanicTestFunc) (bool, interface{}) {\n\n\tdidPanic := false\n\tvar message interface{}\n\tfunc() {\n\n\t\tdefer func() {\n\t\t\tif message = recover(); message != nil {\n\t\t\t\tdidPanic = true\n\t\t\t}\n\t\t}()\n\n\t\t// call the target function\n\t\tf()\n\n\t}()\n\n\treturn didPanic, message\n\n}\n\n// Panics asserts that the code inside the specified PanicTestFunc panics.\n//\n//   assert.Panics(t, func(){\n//     GoCrazy()\n//   }, \"Calling GoCrazy() should panic\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Panics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {\n\n\tif funcDidPanic, panicValue := didPanic(f); !funcDidPanic {\n\t\treturn Fail(t, fmt.Sprintf(\"func %#v should panic\\n\\r\\tPanic value:\\t%v\", f, panicValue), msgAndArgs...)\n\t}\n\n\treturn true\n}\n\n// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.\n//\n//   assert.NotPanics(t, func(){\n//     RemainCalm()\n//   }, \"Calling RemainCalm() should NOT panic\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc NotPanics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {\n\n\tif funcDidPanic, panicValue := didPanic(f); funcDidPanic {\n\t\treturn Fail(t, fmt.Sprintf(\"func %#v should not panic\\n\\r\\tPanic value:\\t%v\", f, panicValue), msgAndArgs...)\n\t}\n\n\treturn true\n}\n\n// WithinDuration asserts that the two times are within duration delta of each other.\n//\n//   assert.WithinDuration(t, time.Now(), time.Now(), 10*time.Second, \"The difference should not be more than 10s\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc WithinDuration(t TestingT, expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool {\n\n\tdt := expected.Sub(actual)\n\tif dt < -delta || dt > delta {\n\t\treturn Fail(t, fmt.Sprintf(\"Max difference between %v and %v allowed is %v, but difference was %v\", expected, actual, delta, dt), msgAndArgs...)\n\t}\n\n\treturn true\n}\n\nfunc toFloat(x interface{}) (float64, bool) {\n\tvar xf float64\n\txok := true\n\n\tswitch xn := x.(type) {\n\tcase uint8:\n\t\txf = float64(xn)\n\tcase uint16:\n\t\txf = float64(xn)\n\tcase uint32:\n\t\txf = float64(xn)\n\tcase uint64:\n\t\txf = float64(xn)\n\tcase int:\n\t\txf = float64(xn)\n\tcase int8:\n\t\txf = float64(xn)\n\tcase int16:\n\t\txf = float64(xn)\n\tcase int32:\n\t\txf = float64(xn)\n\tcase int64:\n\t\txf = float64(xn)\n\tcase float32:\n\t\txf = float64(xn)\n\tcase float64:\n\t\txf = float64(xn)\n\tdefault:\n\t\txok = false\n\t}\n\n\treturn xf, xok\n}\n\n// InDelta asserts that the two numerals are within delta of each other.\n//\n// \t assert.InDelta(t, math.Pi, (22 / 7.0), 0.01)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc InDelta(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {\n\n\taf, aok := toFloat(expected)\n\tbf, bok := toFloat(actual)\n\n\tif !aok || !bok {\n\t\treturn Fail(t, fmt.Sprintf(\"Parameters must be numerical\"), msgAndArgs...)\n\t}\n\n\tdt := af - bf\n\tif dt < -delta || dt > delta {\n\t\treturn Fail(t, fmt.Sprintf(\"Max difference between %v and %v allowed is %v, but difference was %v\", expected, actual, delta, dt), msgAndArgs...)\n\t}\n\n\treturn true\n}\n\n// min(|expected|, |actual|) * epsilon\nfunc calcEpsilonDelta(expected, actual interface{}, epsilon float64) float64 {\n\taf, aok := toFloat(expected)\n\tbf, bok := toFloat(actual)\n\n\tif !aok || !bok {\n\t\t// invalid input\n\t\treturn 0\n\t}\n\n\tif af < 0 {\n\t\taf = -af\n\t}\n\tif bf < 0 {\n\t\tbf = -bf\n\t}\n\tvar delta float64\n\tif af < bf {\n\t\tdelta = af * epsilon\n\t} else {\n\t\tdelta = bf * epsilon\n\t}\n\treturn delta\n}\n\n// InEpsilon asserts that expected and actual have a relative error less than epsilon\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc InEpsilon(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {\n\tdelta := calcEpsilonDelta(expected, actual, epsilon)\n\n\treturn InDelta(t, expected, actual, delta, msgAndArgs...)\n}\n\n/*\n\tErrors\n*/\n\n// NoError asserts that a function returned no error (i.e. `nil`).\n//\n//   actualObj, err := SomeFunction()\n//   if assert.NoError(t, err) {\n//\t   assert.Equal(t, actualObj, expectedObj)\n//   }\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc NoError(t TestingT, err error, msgAndArgs ...interface{}) bool {\n\tif isNil(err) {\n\t\treturn true\n\t}\n\n\treturn Fail(t, fmt.Sprintf(\"No error is expected but got %v\", err), msgAndArgs...)\n}\n\n// Error asserts that a function returned an error (i.e. not `nil`).\n//\n//   actualObj, err := SomeFunction()\n//   if assert.Error(t, err, \"An error was expected\") {\n//\t   assert.Equal(t, err, expectedError)\n//   }\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Error(t TestingT, err error, msgAndArgs ...interface{}) bool {\n\n\tmessage := messageFromMsgAndArgs(msgAndArgs...)\n\treturn NotNil(t, err, \"An error is expected but got nil. %s\", message)\n\n}\n\n// EqualError asserts that a function returned an error (i.e. not `nil`)\n// and that it is equal to the provided error.\n//\n//   actualObj, err := SomeFunction()\n//   if assert.Error(t, err, \"An error was expected\") {\n//\t   assert.Equal(t, err, expectedError)\n//   }\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) bool {\n\n\tmessage := messageFromMsgAndArgs(msgAndArgs...)\n\tif !NotNil(t, theError, \"An error is expected but got nil. %s\", message) {\n\t\treturn false\n\t}\n\ts := \"An error with value \\\"%s\\\" is expected but got \\\"%s\\\". %s\"\n\treturn Equal(t, theError.Error(), errString,\n\t\ts, errString, theError.Error(), message)\n}\n\n// matchRegexp return true if a specified regexp matches a string.\nfunc matchRegexp(rx interface{}, str interface{}) bool {\n\n\tvar r *regexp.Regexp\n\tif rr, ok := rx.(*regexp.Regexp); ok {\n\t\tr = rr\n\t} else {\n\t\tr = regexp.MustCompile(fmt.Sprint(rx))\n\t}\n\n\treturn (r.FindStringIndex(fmt.Sprint(str)) != nil)\n\n}\n\n// Regexp asserts that a specified regexp matches a string.\n//\n//  assert.Regexp(t, regexp.MustCompile(\"start\"), \"it's starting\")\n//  assert.Regexp(t, \"start...$\", \"it's not starting\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Regexp(t TestingT, rx interface{}, str interface{}) bool {\n\n\tmatch := matchRegexp(rx, str)\n\n\tif !match {\n\t\tFail(t, \"Expect \\\"%s\\\" to match \\\"%s\\\"\")\n\t}\n\n\treturn match\n}\n\n// NotRegexp asserts that a specified regexp does not match a string.\n//\n//  assert.NotRegexp(t, regexp.MustCompile(\"starts\"), \"it's starting\")\n//  assert.NotRegexp(t, \"^start\", \"it's not starting\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc NotRegexp(t TestingT, rx interface{}, str interface{}) bool {\n\tmatch := matchRegexp(rx, str)\n\n\tif match {\n\t\tFail(t, \"Expect \\\"%s\\\" to NOT match \\\"%s\\\"\")\n\t}\n\n\treturn !match\n\n}\n"
  },
  {
    "path": "vendor/github.com/stretchr/testify/assert/assertions_test.go",
    "content": "package assert\n\nimport (\n\t\"errors\"\n\t\"regexp\"\n\t\"testing\"\n\t\"time\"\n)\n\n// AssertionTesterInterface defines an interface to be used for testing assertion methods\ntype AssertionTesterInterface interface {\n\tTestMethod()\n}\n\n// AssertionTesterConformingObject is an object that conforms to the AssertionTesterInterface interface\ntype AssertionTesterConformingObject struct {\n}\n\nfunc (a *AssertionTesterConformingObject) TestMethod() {\n}\n\n// AssertionTesterNonConformingObject is an object that does not conform to the AssertionTesterInterface interface\ntype AssertionTesterNonConformingObject struct {\n}\n\nfunc TestObjectsAreEqual(t *testing.T) {\n\n\tif !ObjectsAreEqual(\"Hello World\", \"Hello World\") {\n\t\tt.Error(\"objectsAreEqual should return true\")\n\t}\n\tif !ObjectsAreEqual(123, 123) {\n\t\tt.Error(\"objectsAreEqual should return true\")\n\t}\n\tif !ObjectsAreEqual(123.5, 123.5) {\n\t\tt.Error(\"objectsAreEqual should return true\")\n\t}\n\tif !ObjectsAreEqual([]byte(\"Hello World\"), []byte(\"Hello World\")) {\n\t\tt.Error(\"objectsAreEqual should return true\")\n\t}\n\tif !ObjectsAreEqual(nil, nil) {\n\t\tt.Error(\"objectsAreEqual should return true\")\n\t}\n\n}\n\nfunc TestImplements(t *testing.T) {\n\n\tmockT := new(testing.T)\n\n\tif !Implements(mockT, (*AssertionTesterInterface)(nil), new(AssertionTesterConformingObject)) {\n\t\tt.Error(\"Implements method should return true: AssertionTesterConformingObject implements AssertionTesterInterface\")\n\t}\n\tif Implements(mockT, (*AssertionTesterInterface)(nil), new(AssertionTesterNonConformingObject)) {\n\t\tt.Error(\"Implements method should return false: AssertionTesterNonConformingObject does not implements AssertionTesterInterface\")\n\t}\n\n}\n\nfunc TestIsType(t *testing.T) {\n\n\tmockT := new(testing.T)\n\n\tif !IsType(mockT, new(AssertionTesterConformingObject), new(AssertionTesterConformingObject)) {\n\t\tt.Error(\"IsType should return true: AssertionTesterConformingObject is the same type as AssertionTesterConformingObject\")\n\t}\n\tif IsType(mockT, new(AssertionTesterConformingObject), new(AssertionTesterNonConformingObject)) {\n\t\tt.Error(\"IsType should return false: AssertionTesterConformingObject is not the same type as AssertionTesterNonConformingObject\")\n\t}\n\n}\n\nfunc TestEqual(t *testing.T) {\n\n\tmockT := new(testing.T)\n\n\tif !Equal(mockT, \"Hello World\", \"Hello World\") {\n\t\tt.Error(\"Equal should return true\")\n\t}\n\tif !Equal(mockT, 123, 123) {\n\t\tt.Error(\"Equal should return true\")\n\t}\n\tif !Equal(mockT, 123.5, 123.5) {\n\t\tt.Error(\"Equal should return true\")\n\t}\n\tif !Equal(mockT, []byte(\"Hello World\"), []byte(\"Hello World\")) {\n\t\tt.Error(\"Equal should return true\")\n\t}\n\tif !Equal(mockT, nil, nil) {\n\t\tt.Error(\"Equal should return true\")\n\t}\n\tif !Equal(mockT, int32(123), int64(123)) {\n\t\tt.Error(\"Equal should return true\")\n\t}\n\tif !Equal(mockT, int64(123), uint64(123)) {\n\t\tt.Error(\"Equal should return true\")\n\t}\n\n}\n\nfunc TestNotNil(t *testing.T) {\n\n\tmockT := new(testing.T)\n\n\tif !NotNil(mockT, new(AssertionTesterConformingObject)) {\n\t\tt.Error(\"NotNil should return true: object is not nil\")\n\t}\n\tif NotNil(mockT, nil) {\n\t\tt.Error(\"NotNil should return false: object is nil\")\n\t}\n\n}\n\nfunc TestNil(t *testing.T) {\n\n\tmockT := new(testing.T)\n\n\tif !Nil(mockT, nil) {\n\t\tt.Error(\"Nil should return true: object is nil\")\n\t}\n\tif Nil(mockT, new(AssertionTesterConformingObject)) {\n\t\tt.Error(\"Nil should return false: object is not nil\")\n\t}\n\n}\n\nfunc TestTrue(t *testing.T) {\n\n\tmockT := new(testing.T)\n\n\tif !True(mockT, true) {\n\t\tt.Error(\"True should return true\")\n\t}\n\tif True(mockT, false) {\n\t\tt.Error(\"True should return false\")\n\t}\n\n}\n\nfunc TestFalse(t *testing.T) {\n\n\tmockT := new(testing.T)\n\n\tif !False(mockT, false) {\n\t\tt.Error(\"False should return true\")\n\t}\n\tif False(mockT, true) {\n\t\tt.Error(\"False should return false\")\n\t}\n\n}\n\nfunc TestExactly(t *testing.T) {\n\n\tmockT := new(testing.T)\n\n\ta := float32(1)\n\tb := float64(1)\n\tc := float32(1)\n\td := float32(2)\n\n\tif Exactly(mockT, a, b) {\n\t\tt.Error(\"Exactly should return false\")\n\t}\n\tif Exactly(mockT, a, d) {\n\t\tt.Error(\"Exactly should return false\")\n\t}\n\tif !Exactly(mockT, a, c) {\n\t\tt.Error(\"Exactly should return true\")\n\t}\n\n\tif Exactly(mockT, nil, a) {\n\t\tt.Error(\"Exactly should return false\")\n\t}\n\tif Exactly(mockT, a, nil) {\n\t\tt.Error(\"Exactly should return false\")\n\t}\n\n}\n\nfunc TestNotEqual(t *testing.T) {\n\n\tmockT := new(testing.T)\n\n\tif !NotEqual(mockT, \"Hello World\", \"Hello World!\") {\n\t\tt.Error(\"NotEqual should return true\")\n\t}\n\tif !NotEqual(mockT, 123, 1234) {\n\t\tt.Error(\"NotEqual should return true\")\n\t}\n\tif !NotEqual(mockT, 123.5, 123.55) {\n\t\tt.Error(\"NotEqual should return true\")\n\t}\n\tif !NotEqual(mockT, []byte(\"Hello World\"), []byte(\"Hello World!\")) {\n\t\tt.Error(\"NotEqual should return true\")\n\t}\n\tif !NotEqual(mockT, nil, new(AssertionTesterConformingObject)) {\n\t\tt.Error(\"NotEqual should return true\")\n\t}\n\n\tif NotEqual(mockT, \"Hello World\", \"Hello World\") {\n\t\tt.Error(\"NotEqual should return false\")\n\t}\n\tif NotEqual(mockT, 123, 123) {\n\t\tt.Error(\"NotEqual should return false\")\n\t}\n\tif NotEqual(mockT, 123.5, 123.5) {\n\t\tt.Error(\"NotEqual should return false\")\n\t}\n\tif NotEqual(mockT, []byte(\"Hello World\"), []byte(\"Hello World\")) {\n\t\tt.Error(\"NotEqual should return false\")\n\t}\n\tif NotEqual(mockT, new(AssertionTesterConformingObject), new(AssertionTesterConformingObject)) {\n\t\tt.Error(\"NotEqual should return false\")\n\t}\n}\n\nfunc TestContains(t *testing.T) {\n\n\tmockT := new(testing.T)\n\tlist := []string{\"Foo\", \"Bar\"}\n\n\tif !Contains(mockT, \"Hello World\", \"Hello\") {\n\t\tt.Error(\"Contains should return true: \\\"Hello World\\\" contains \\\"Hello\\\"\")\n\t}\n\tif Contains(mockT, \"Hello World\", \"Salut\") {\n\t\tt.Error(\"Contains should return false: \\\"Hello World\\\" does not contain \\\"Salut\\\"\")\n\t}\n\n\tif !Contains(mockT, list, \"Bar\") {\n\t\tt.Error(\"Contains should return true: \\\"[\\\"Foo\\\", \\\"Bar\\\"]\\\" contains \\\"Bar\\\"\")\n\t}\n\tif Contains(mockT, list, \"Salut\") {\n\t\tt.Error(\"Contains should return false: \\\"[\\\"Foo\\\", \\\"Bar\\\"]\\\" does not contain \\\"Salut\\\"\")\n\t}\n\n}\n\nfunc TestNotContains(t *testing.T) {\n\n\tmockT := new(testing.T)\n\tlist := []string{\"Foo\", \"Bar\"}\n\n\tif !NotContains(mockT, \"Hello World\", \"Hello!\") {\n\t\tt.Error(\"NotContains should return true: \\\"Hello World\\\" does not contain \\\"Hello!\\\"\")\n\t}\n\tif NotContains(mockT, \"Hello World\", \"Hello\") {\n\t\tt.Error(\"NotContains should return false: \\\"Hello World\\\" contains \\\"Hello\\\"\")\n\t}\n\n\tif !NotContains(mockT, list, \"Foo!\") {\n\t\tt.Error(\"NotContains should return true: \\\"[\\\"Foo\\\", \\\"Bar\\\"]\\\" does not contain \\\"Foo!\\\"\")\n\t}\n\tif NotContains(mockT, list, \"Foo\") {\n\t\tt.Error(\"NotContains should return false: \\\"[\\\"Foo\\\", \\\"Bar\\\"]\\\" contains \\\"Foo\\\"\")\n\t}\n\n}\n\nfunc Test_includeElement(t *testing.T) {\n\n\tlist1 := []string{\"Foo\", \"Bar\"}\n\tlist2 := []int{1, 2}\n\n\tok, found := includeElement(\"Hello World\", \"World\")\n\tTrue(t, ok)\n\tTrue(t, found)\n\n\tok, found = includeElement(list1, \"Foo\")\n\tTrue(t, ok)\n\tTrue(t, found)\n\n\tok, found = includeElement(list1, \"Bar\")\n\tTrue(t, ok)\n\tTrue(t, found)\n\n\tok, found = includeElement(list2, 1)\n\tTrue(t, ok)\n\tTrue(t, found)\n\n\tok, found = includeElement(list2, 2)\n\tTrue(t, ok)\n\tTrue(t, found)\n\n\tok, found = includeElement(list1, \"Foo!\")\n\tTrue(t, ok)\n\tFalse(t, found)\n\n\tok, found = includeElement(list2, 3)\n\tTrue(t, ok)\n\tFalse(t, found)\n\n\tok, found = includeElement(list2, \"1\")\n\tTrue(t, ok)\n\tFalse(t, found)\n\n\tok, found = includeElement(1433, \"1\")\n\tFalse(t, ok)\n\tFalse(t, found)\n\n}\n\nfunc TestCondition(t *testing.T) {\n\tmockT := new(testing.T)\n\n\tif !Condition(mockT, func() bool { return true }, \"Truth\") {\n\t\tt.Error(\"Condition should return true\")\n\t}\n\n\tif Condition(mockT, func() bool { return false }, \"Lie\") {\n\t\tt.Error(\"Condition should return false\")\n\t}\n\n}\n\nfunc TestDidPanic(t *testing.T) {\n\n\tif funcDidPanic, _ := didPanic(func() {\n\t\tpanic(\"Panic!\")\n\t}); !funcDidPanic {\n\t\tt.Error(\"didPanic should return true\")\n\t}\n\n\tif funcDidPanic, _ := didPanic(func() {\n\t}); funcDidPanic {\n\t\tt.Error(\"didPanic should return false\")\n\t}\n\n}\n\nfunc TestPanics(t *testing.T) {\n\n\tmockT := new(testing.T)\n\n\tif !Panics(mockT, func() {\n\t\tpanic(\"Panic!\")\n\t}) {\n\t\tt.Error(\"Panics should return true\")\n\t}\n\n\tif Panics(mockT, func() {\n\t}) {\n\t\tt.Error(\"Panics should return false\")\n\t}\n\n}\n\nfunc TestNotPanics(t *testing.T) {\n\n\tmockT := new(testing.T)\n\n\tif !NotPanics(mockT, func() {\n\t}) {\n\t\tt.Error(\"NotPanics should return true\")\n\t}\n\n\tif NotPanics(mockT, func() {\n\t\tpanic(\"Panic!\")\n\t}) {\n\t\tt.Error(\"NotPanics should return false\")\n\t}\n\n}\n\nfunc TestEqual_Funcs(t *testing.T) {\n\n\ttype f func() int\n\tf1 := func() int { return 1 }\n\tf2 := func() int { return 2 }\n\n\tf1Copy := f1\n\n\tEqual(t, f1Copy, f1, \"Funcs are the same and should be considered equal\")\n\tNotEqual(t, f1, f2, \"f1 and f2 are different\")\n\n}\n\nfunc TestNoError(t *testing.T) {\n\n\tmockT := new(testing.T)\n\n\t// start with a nil error\n\tvar err error\n\n\tTrue(t, NoError(mockT, err), \"NoError should return True for nil arg\")\n\n\t// now set an error\n\terr = errors.New(\"some error\")\n\n\tFalse(t, NoError(mockT, err), \"NoError with error should return False\")\n\n}\n\nfunc TestError(t *testing.T) {\n\n\tmockT := new(testing.T)\n\n\t// start with a nil error\n\tvar err error\n\n\tFalse(t, Error(mockT, err), \"Error should return False for nil arg\")\n\n\t// now set an error\n\terr = errors.New(\"some error\")\n\n\tTrue(t, Error(mockT, err), \"Error with error should return True\")\n\n}\n\nfunc TestEqualError(t *testing.T) {\n\tmockT := new(testing.T)\n\n\t// start with a nil error\n\tvar err error\n\tFalse(t, EqualError(mockT, err, \"\"),\n\t\t\"EqualError should return false for nil arg\")\n\n\t// now set an error\n\terr = errors.New(\"some error\")\n\tFalse(t, EqualError(mockT, err, \"Not some error\"),\n\t\t\"EqualError should return false for different error string\")\n\tTrue(t, EqualError(mockT, err, \"some error\"),\n\t\t\"EqualError should return true\")\n}\n\nfunc Test_isEmpty(t *testing.T) {\n\n\tchWithValue := make(chan struct{}, 1)\n\tchWithValue <- struct{}{}\n\n\tTrue(t, isEmpty(\"\"))\n\tTrue(t, isEmpty(nil))\n\tTrue(t, isEmpty([]string{}))\n\tTrue(t, isEmpty(0))\n\tTrue(t, isEmpty(int32(0)))\n\tTrue(t, isEmpty(int64(0)))\n\tTrue(t, isEmpty(false))\n\tTrue(t, isEmpty(map[string]string{}))\n\tTrue(t, isEmpty(new(time.Time)))\n\tTrue(t, isEmpty(make(chan struct{})))\n\tFalse(t, isEmpty(\"something\"))\n\tFalse(t, isEmpty(errors.New(\"something\")))\n\tFalse(t, isEmpty([]string{\"something\"}))\n\tFalse(t, isEmpty(1))\n\tFalse(t, isEmpty(true))\n\tFalse(t, isEmpty(map[string]string{\"Hello\": \"World\"}))\n\tFalse(t, isEmpty(chWithValue))\n\n}\n\nfunc TestEmpty(t *testing.T) {\n\n\tmockT := new(testing.T)\n\tchWithValue := make(chan struct{}, 1)\n\tchWithValue <- struct{}{}\n\n\tTrue(t, Empty(mockT, \"\"), \"Empty string is empty\")\n\tTrue(t, Empty(mockT, nil), \"Nil is empty\")\n\tTrue(t, Empty(mockT, []string{}), \"Empty string array is empty\")\n\tTrue(t, Empty(mockT, 0), \"Zero int value is empty\")\n\tTrue(t, Empty(mockT, false), \"False value is empty\")\n\tTrue(t, Empty(mockT, make(chan struct{})), \"Channel without values is empty\")\n\n\tFalse(t, Empty(mockT, \"something\"), \"Non Empty string is not empty\")\n\tFalse(t, Empty(mockT, errors.New(\"something\")), \"Non nil object is not empty\")\n\tFalse(t, Empty(mockT, []string{\"something\"}), \"Non empty string array is not empty\")\n\tFalse(t, Empty(mockT, 1), \"Non-zero int value is not empty\")\n\tFalse(t, Empty(mockT, true), \"True value is not empty\")\n\tFalse(t, Empty(mockT, chWithValue), \"Channel with values is not empty\")\n}\n\nfunc TestNotEmpty(t *testing.T) {\n\n\tmockT := new(testing.T)\n\tchWithValue := make(chan struct{}, 1)\n\tchWithValue <- struct{}{}\n\n\tFalse(t, NotEmpty(mockT, \"\"), \"Empty string is empty\")\n\tFalse(t, NotEmpty(mockT, nil), \"Nil is empty\")\n\tFalse(t, NotEmpty(mockT, []string{}), \"Empty string array is empty\")\n\tFalse(t, NotEmpty(mockT, 0), \"Zero int value is empty\")\n\tFalse(t, NotEmpty(mockT, false), \"False value is empty\")\n\tFalse(t, NotEmpty(mockT, make(chan struct{})), \"Channel without values is empty\")\n\n\tTrue(t, NotEmpty(mockT, \"something\"), \"Non Empty string is not empty\")\n\tTrue(t, NotEmpty(mockT, errors.New(\"something\")), \"Non nil object is not empty\")\n\tTrue(t, NotEmpty(mockT, []string{\"something\"}), \"Non empty string array is not empty\")\n\tTrue(t, NotEmpty(mockT, 1), \"Non-zero int value is not empty\")\n\tTrue(t, NotEmpty(mockT, true), \"True value is not empty\")\n\tTrue(t, NotEmpty(mockT, chWithValue), \"Channel with values is not empty\")\n}\n\nfunc Test_getLen(t *testing.T) {\n\tfalseCases := []interface{}{\n\t\tnil,\n\t\t0,\n\t\ttrue,\n\t\tfalse,\n\t\t'A',\n\t\tstruct{}{},\n\t}\n\tfor _, v := range falseCases {\n\t\tok, l := getLen(v)\n\t\tFalse(t, ok, \"Expected getLen fail to get length of %#v\", v)\n\t\tEqual(t, 0, l, \"getLen should return 0 for %#v\", v)\n\t}\n\n\tch := make(chan int, 5)\n\tch <- 1\n\tch <- 2\n\tch <- 3\n\ttrueCases := []struct {\n\t\tv interface{}\n\t\tl int\n\t}{\n\t\t{[]int{1, 2, 3}, 3},\n\t\t{[...]int{1, 2, 3}, 3},\n\t\t{\"ABC\", 3},\n\t\t{map[int]int{1: 2, 2: 4, 3: 6}, 3},\n\t\t{ch, 3},\n\n\t\t{[]int{}, 0},\n\t\t{map[int]int{}, 0},\n\t\t{make(chan int), 0},\n\n\t\t{[]int(nil), 0},\n\t\t{map[int]int(nil), 0},\n\t\t{(chan int)(nil), 0},\n\t}\n\n\tfor _, c := range trueCases {\n\t\tok, l := getLen(c.v)\n\t\tTrue(t, ok, \"Expected getLen success to get length of %#v\", c.v)\n\t\tEqual(t, c.l, l)\n\t}\n}\n\nfunc TestLen(t *testing.T) {\n\tmockT := new(testing.T)\n\n\tFalse(t, Len(mockT, nil, 0), \"nil does not have length\")\n\tFalse(t, Len(mockT, 0, 0), \"int does not have length\")\n\tFalse(t, Len(mockT, true, 0), \"true does not have length\")\n\tFalse(t, Len(mockT, false, 0), \"false does not have length\")\n\tFalse(t, Len(mockT, 'A', 0), \"Rune does not have length\")\n\tFalse(t, Len(mockT, struct{}{}, 0), \"Struct does not have length\")\n\n\tch := make(chan int, 5)\n\tch <- 1\n\tch <- 2\n\tch <- 3\n\n\tcases := []struct {\n\t\tv interface{}\n\t\tl int\n\t}{\n\t\t{[]int{1, 2, 3}, 3},\n\t\t{[...]int{1, 2, 3}, 3},\n\t\t{\"ABC\", 3},\n\t\t{map[int]int{1: 2, 2: 4, 3: 6}, 3},\n\t\t{ch, 3},\n\n\t\t{[]int{}, 0},\n\t\t{map[int]int{}, 0},\n\t\t{make(chan int), 0},\n\n\t\t{[]int(nil), 0},\n\t\t{map[int]int(nil), 0},\n\t\t{(chan int)(nil), 0},\n\t}\n\n\tfor _, c := range cases {\n\t\tTrue(t, Len(mockT, c.v, c.l), \"%#v have %d items\", c.v, c.l)\n\t}\n\n\tcases = []struct {\n\t\tv interface{}\n\t\tl int\n\t}{\n\t\t{[]int{1, 2, 3}, 4},\n\t\t{[...]int{1, 2, 3}, 2},\n\t\t{\"ABC\", 2},\n\t\t{map[int]int{1: 2, 2: 4, 3: 6}, 4},\n\t\t{ch, 2},\n\n\t\t{[]int{}, 1},\n\t\t{map[int]int{}, 1},\n\t\t{make(chan int), 1},\n\n\t\t{[]int(nil), 1},\n\t\t{map[int]int(nil), 1},\n\t\t{(chan int)(nil), 1},\n\t}\n\n\tfor _, c := range cases {\n\t\tFalse(t, Len(mockT, c.v, c.l), \"%#v have %d items\", c.v, c.l)\n\t}\n}\n\nfunc TestWithinDuration(t *testing.T) {\n\n\tmockT := new(testing.T)\n\ta := time.Now()\n\tb := a.Add(10 * time.Second)\n\n\tTrue(t, WithinDuration(mockT, a, b, 10*time.Second), \"A 10s difference is within a 10s time difference\")\n\tTrue(t, WithinDuration(mockT, b, a, 10*time.Second), \"A 10s difference is within a 10s time difference\")\n\n\tFalse(t, WithinDuration(mockT, a, b, 9*time.Second), \"A 10s difference is not within a 9s time difference\")\n\tFalse(t, WithinDuration(mockT, b, a, 9*time.Second), \"A 10s difference is not within a 9s time difference\")\n\n\tFalse(t, WithinDuration(mockT, a, b, -9*time.Second), \"A 10s difference is not within a 9s time difference\")\n\tFalse(t, WithinDuration(mockT, b, a, -9*time.Second), \"A 10s difference is not within a 9s time difference\")\n\n\tFalse(t, WithinDuration(mockT, a, b, -11*time.Second), \"A 10s difference is not within a 9s time difference\")\n\tFalse(t, WithinDuration(mockT, b, a, -11*time.Second), \"A 10s difference is not within a 9s time difference\")\n}\n\nfunc TestInDelta(t *testing.T) {\n\tmockT := new(testing.T)\n\n\tTrue(t, InDelta(mockT, 1.001, 1, 0.01), \"|1.001 - 1| <= 0.01\")\n\tTrue(t, InDelta(mockT, 1, 1.001, 0.01), \"|1 - 1.001| <= 0.01\")\n\tTrue(t, InDelta(mockT, 1, 2, 1), \"|1 - 2| <= 1\")\n\tFalse(t, InDelta(mockT, 1, 2, 0.5), \"Expected |1 - 2| <= 0.5 to fail\")\n\tFalse(t, InDelta(mockT, 2, 1, 0.5), \"Expected |2 - 1| <= 0.5 to fail\")\n\tFalse(t, InDelta(mockT, \"\", nil, 1), \"Expected non numerals to fail\")\n\n\tcases := []struct {\n\t\ta, b  interface{}\n\t\tdelta float64\n\t}{\n\t\t{uint8(2), uint8(1), 1},\n\t\t{uint16(2), uint16(1), 1},\n\t\t{uint32(2), uint32(1), 1},\n\t\t{uint64(2), uint64(1), 1},\n\n\t\t{int(2), int(1), 1},\n\t\t{int8(2), int8(1), 1},\n\t\t{int16(2), int16(1), 1},\n\t\t{int32(2), int32(1), 1},\n\t\t{int64(2), int64(1), 1},\n\n\t\t{float32(2), float32(1), 1},\n\t\t{float64(2), float64(1), 1},\n\t}\n\n\tfor _, tc := range cases {\n\t\tTrue(t, InDelta(mockT, tc.a, tc.b, tc.delta), \"Expected |%V - %V| <= %v\", tc.a, tc.b, tc.delta)\n\t}\n}\n\nfunc TestInEpsilon(t *testing.T) {\n\tmockT := new(testing.T)\n\n\tcases := []struct {\n\t\ta, b    interface{}\n\t\tepsilon float64\n\t}{\n\t\t{uint8(2), uint16(2), .001},\n\t\t{2.1, 2.2, 0.1},\n\t\t{2.2, 2.1, 0.1},\n\t\t{-2.1, -2.2, 0.1},\n\t\t{-2.2, -2.1, 0.1},\n\t\t{uint64(100), uint8(101), 0.01},\n\t\t{0.1, -0.1, 2},\n\t}\n\n\tfor _, tc := range cases {\n\t\tTrue(t, InEpsilon(mockT, tc.a, tc.b, tc.epsilon, \"Expected %V and %V to have a relative difference of %v\", tc.a, tc.b, tc.epsilon))\n\t}\n\n\tcases = []struct {\n\t\ta, b    interface{}\n\t\tepsilon float64\n\t}{\n\t\t{uint8(2), int16(-2), .001},\n\t\t{uint64(100), uint8(102), 0.01},\n\t\t{2.1, 2.2, 0.001},\n\t\t{2.2, 2.1, 0.001},\n\t\t{2.1, -2.2, 1},\n\t\t{2.1, \"bla-bla\", 0},\n\t\t{0.1, -0.1, 1.99},\n\t}\n\n\tfor _, tc := range cases {\n\t\tFalse(t, InEpsilon(mockT, tc.a, tc.b, tc.epsilon, \"Expected %V and %V to have a relative difference of %v\", tc.a, tc.b, tc.epsilon))\n\t}\n\n}\n\nfunc TestRegexp(t *testing.T) {\n\tmockT := new(testing.T)\n\n\tcases := []struct {\n\t\trx, str string\n\t}{\n\t\t{\"^start\", \"start of the line\"},\n\t\t{\"end$\", \"in the end\"},\n\t\t{\"[0-9]{3}[.-]?[0-9]{2}[.-]?[0-9]{2}\", \"My phone number is 650.12.34\"},\n\t}\n\n\tfor _, tc := range cases {\n\t\tTrue(t, Regexp(mockT, tc.rx, tc.str))\n\t\tTrue(t, Regexp(mockT, regexp.MustCompile(tc.rx), tc.str))\n\t\tFalse(t, NotRegexp(mockT, tc.rx, tc.str))\n\t\tFalse(t, NotRegexp(mockT, regexp.MustCompile(tc.rx), tc.str))\n\t}\n\n\tcases = []struct {\n\t\trx, str string\n\t}{\n\t\t{\"^asdfastart\", \"Not the start of the line\"},\n\t\t{\"end$\", \"in the end.\"},\n\t\t{\"[0-9]{3}[.-]?[0-9]{2}[.-]?[0-9]{2}\", \"My phone number is 650.12a.34\"},\n\t}\n\n\tfor _, tc := range cases {\n\t\tFalse(t, Regexp(mockT, tc.rx, tc.str), \"Expected \\\"%s\\\" to not match \\\"%s\\\"\", tc.rx, tc.str)\n\t\tFalse(t, Regexp(mockT, regexp.MustCompile(tc.rx), tc.str))\n\t\tTrue(t, NotRegexp(mockT, tc.rx, tc.str))\n\t\tTrue(t, NotRegexp(mockT, regexp.MustCompile(tc.rx), tc.str))\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/stretchr/testify/assert/doc.go",
    "content": "// A set of comprehensive testing tools for use with the normal Go testing system.\n//\n// Example Usage\n//\n// The following is a complete example using assert in a standard test function:\n//    import (\n//      \"testing\"\n//      \"github.com/stretchr/testify/assert\"\n//    )\n//\n//    func TestSomething(t *testing.T) {\n//\n//      var a string = \"Hello\"\n//      var b string = \"Hello\"\n//\n//      assert.Equal(t, a, b, \"The two words should be the same.\")\n//\n//    }\n//\n// if you assert many times, use the below:\n//\n//    import (\n//      \"testing\"\n//      \"github.com/stretchr/testify/assert\"\n//    )\n//\n//    func TestSomething(t *testing.T) {\n//      assert := assert.New(t)\n//\n//      var a string = \"Hello\"\n//      var b string = \"Hello\"\n//\n//      assert.Equal(a, b, \"The two words should be the same.\")\n//    }\n//\n// Assertions\n//\n// Assertions allow you to easily write test code, and are global funcs in the `assert` package.\n// All assertion functions take, as the first argument, the `*testing.T` object provided by the\n// testing framework. This allows the assertion funcs to write the failings and other details to\n// the correct place.\n//\n// Every assertion function also takes an optional string message as the final argument,\n// allowing custom error messages to be appended to the message the assertion method outputs.\n//\n// Here is an overview of the assert functions:\n//\n//    assert.Equal(t, expected, actual [, message [, format-args])\n//\n//    assert.NotEqual(t, notExpected, actual [, message [, format-args]])\n//\n//    assert.True(t, actualBool [, message [, format-args]])\n//\n//    assert.False(t, actualBool [, message [, format-args]])\n//\n//    assert.Nil(t, actualObject [, message [, format-args]])\n//\n//    assert.NotNil(t, actualObject [, message [, format-args]])\n//\n//    assert.Empty(t, actualObject [, message [, format-args]])\n//\n//    assert.NotEmpty(t, actualObject [, message [, format-args]])\n//\n//    assert.Len(t, actualObject, expectedLength, [, message [, format-args]])\n//\n//    assert.Error(t, errorObject [, message [, format-args]])\n//\n//    assert.NoError(t, errorObject [, message [, format-args]])\n//\n//    assert.EqualError(t, theError, errString [, message [, format-args]])\n//\n//    assert.Implements(t, (*MyInterface)(nil), new(MyObject) [,message [, format-args]])\n//\n//    assert.IsType(t, expectedObject, actualObject [, message [, format-args]])\n//\n//    assert.Contains(t, stringOrSlice, substringOrElement [, message [, format-args]])\n//\n//    assert.NotContains(t, stringOrSlice, substringOrElement [, message [, format-args]])\n//\n//    assert.Panics(t, func(){\n//\n//\t    // call code that should panic\n//\n//    } [, message [, format-args]])\n//\n//    assert.NotPanics(t, func(){\n//\n//\t    // call code that should not panic\n//\n//    } [, message [, format-args]])\n//\n//    assert.WithinDuration(t, timeA, timeB, deltaTime, [, message [, format-args]])\n//\n//    assert.InDelta(t, numA, numB, delta, [, message [, format-args]])\n//\n//    assert.InEpsilon(t, numA, numB, epsilon, [, message [, format-args]])\n//\n// assert package contains Assertions object. it has assertion methods.\n//\n// Here is an overview of the assert functions:\n//    assert.Equal(expected, actual [, message [, format-args])\n//\n//    assert.NotEqual(notExpected, actual [, message [, format-args]])\n//\n//    assert.True(actualBool [, message [, format-args]])\n//\n//    assert.False(actualBool [, message [, format-args]])\n//\n//    assert.Nil(actualObject [, message [, format-args]])\n//\n//    assert.NotNil(actualObject [, message [, format-args]])\n//\n//    assert.Empty(actualObject [, message [, format-args]])\n//\n//    assert.NotEmpty(actualObject [, message [, format-args]])\n//\n//    assert.Len(actualObject, expectedLength, [, message [, format-args]])\n//\n//    assert.Error(errorObject [, message [, format-args]])\n//\n//    assert.NoError(errorObject [, message [, format-args]])\n//\n//    assert.EqualError(theError, errString [, message [, format-args]])\n//\n//    assert.Implements((*MyInterface)(nil), new(MyObject) [,message [, format-args]])\n//\n//    assert.IsType(expectedObject, actualObject [, message [, format-args]])\n//\n//    assert.Contains(stringOrSlice, substringOrElement [, message [, format-args]])\n//\n//    assert.NotContains(stringOrSlice, substringOrElement [, message [, format-args]])\n//\n//    assert.Panics(func(){\n//\n//\t    // call code that should panic\n//\n//    } [, message [, format-args]])\n//\n//    assert.NotPanics(func(){\n//\n//\t    // call code that should not panic\n//\n//    } [, message [, format-args]])\n//\n//    assert.WithinDuration(timeA, timeB, deltaTime, [, message [, format-args]])\n//\n//    assert.InDelta(numA, numB, delta, [, message [, format-args]])\n//\n//    assert.InEpsilon(numA, numB, epsilon, [, message [, format-args]])\npackage assert\n"
  },
  {
    "path": "vendor/github.com/stretchr/testify/assert/errors.go",
    "content": "package assert\n\nimport (\n\t\"errors\"\n)\n\n// AnError is an error instance useful for testing.  If the code does not care\n// about error specifics, and only needs to return the error for example, this\n// error should be used to make the test code more readable.\nvar AnError = errors.New(\"assert.AnError general error for testing\")\n"
  },
  {
    "path": "vendor/github.com/stretchr/testify/assert/forward_assertions.go",
    "content": "package assert\n\nimport \"time\"\n\ntype Assertions struct {\n\tt TestingT\n}\n\nfunc New(t TestingT) *Assertions {\n\treturn &Assertions{\n\t\tt: t,\n\t}\n}\n\n// Fail reports a failure through\nfunc (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface{}) bool {\n\treturn Fail(a.t, failureMessage, msgAndArgs...)\n}\n\n// Implements asserts that an object is implemented by the specified interface.\n//\n//    assert.Implements((*MyInterface)(nil), new(MyObject), \"MyObject\")\nfunc (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool {\n\treturn Implements(a.t, interfaceObject, object, msgAndArgs...)\n}\n\n// IsType asserts that the specified objects are of the same type.\nfunc (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool {\n\treturn IsType(a.t, expectedType, object, msgAndArgs...)\n}\n\n// Equal asserts that two objects are equal.\n//\n//    assert.Equal(123, 123, \"123 and 123 should be equal\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Equal(expected, actual interface{}, msgAndArgs ...interface{}) bool {\n\treturn Equal(a.t, expected, actual, msgAndArgs...)\n}\n\n// Exactly asserts that two objects are equal is value and type.\n//\n//    assert.Exactly(int32(123), int64(123), \"123 and 123 should NOT be equal\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Exactly(expected, actual interface{}, msgAndArgs ...interface{}) bool {\n\treturn Exactly(a.t, expected, actual, msgAndArgs...)\n}\n\n// NotNil asserts that the specified object is not nil.\n//\n//    assert.NotNil(err, \"err should be something\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) bool {\n\treturn NotNil(a.t, object, msgAndArgs...)\n}\n\n// Nil asserts that the specified object is nil.\n//\n//    assert.Nil(err, \"err should be nothing\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) bool {\n\treturn Nil(a.t, object, msgAndArgs...)\n}\n\n// Empty asserts that the specified object is empty.  I.e. nil, \"\", false, 0 or a\n// slice with len == 0.\n//\n// assert.Empty(obj)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) bool {\n\treturn Empty(a.t, object, msgAndArgs...)\n}\n\n// Empty asserts that the specified object is NOT empty.  I.e. not nil, \"\", false, 0 or a\n// slice with len == 0.\n//\n// if assert.NotEmpty(obj) {\n//   assert.Equal(\"two\", obj[1])\n// }\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) bool {\n\treturn NotEmpty(a.t, object, msgAndArgs...)\n}\n\n// Len asserts that the specified object has specific length.\n// Len also fails if the object has a type that len() not accept.\n//\n//    assert.Len(mySlice, 3, \"The size of slice is not 3\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) bool {\n\treturn Len(a.t, object, length, msgAndArgs...)\n}\n\n// True asserts that the specified value is true.\n//\n//    assert.True(myBool, \"myBool should be true\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) True(value bool, msgAndArgs ...interface{}) bool {\n\treturn True(a.t, value, msgAndArgs...)\n}\n\n// False asserts that the specified value is true.\n//\n//    assert.False(myBool, \"myBool should be false\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) False(value bool, msgAndArgs ...interface{}) bool {\n\treturn False(a.t, value, msgAndArgs...)\n}\n\n// NotEqual asserts that the specified values are NOT equal.\n//\n//    assert.NotEqual(obj1, obj2, \"two objects shouldn't be equal\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) NotEqual(expected, actual interface{}, msgAndArgs ...interface{}) bool {\n\treturn NotEqual(a.t, expected, actual, msgAndArgs...)\n}\n\n// Contains asserts that the specified string contains the specified substring.\n//\n//    assert.Contains(\"Hello World\", \"World\", \"But 'Hello World' does contain 'World'\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Contains(s, contains interface{}, msgAndArgs ...interface{}) bool {\n\treturn Contains(a.t, s, contains, msgAndArgs...)\n}\n\n// NotContains asserts that the specified string does NOT contain the specified substring.\n//\n//    assert.NotContains(\"Hello World\", \"Earth\", \"But 'Hello World' does NOT contain 'Earth'\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) NotContains(s, contains interface{}, msgAndArgs ...interface{}) bool {\n\treturn NotContains(a.t, s, contains, msgAndArgs...)\n}\n\n// Uses a Comparison to assert a complex condition.\nfunc (a *Assertions) Condition(comp Comparison, msgAndArgs ...interface{}) bool {\n\treturn Condition(a.t, comp, msgAndArgs...)\n}\n\n// Panics asserts that the code inside the specified PanicTestFunc panics.\n//\n//   assert.Panics(func(){\n//     GoCrazy()\n//   }, \"Calling GoCrazy() should panic\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Panics(f PanicTestFunc, msgAndArgs ...interface{}) bool {\n\treturn Panics(a.t, f, msgAndArgs...)\n}\n\n// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.\n//\n//   assert.NotPanics(func(){\n//     RemainCalm()\n//   }, \"Calling RemainCalm() should NOT panic\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) NotPanics(f PanicTestFunc, msgAndArgs ...interface{}) bool {\n\treturn NotPanics(a.t, f, msgAndArgs...)\n}\n\n// WithinDuration asserts that the two times are within duration delta of each other.\n//\n//   assert.WithinDuration(time.Now(), time.Now(), 10*time.Second, \"The difference should not be more than 10s\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) WithinDuration(expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool {\n\treturn WithinDuration(a.t, expected, actual, delta, msgAndArgs...)\n}\n\n// InDelta asserts that the two numerals are within delta of each other.\n//\n// \t assert.InDelta(t, math.Pi, (22 / 7.0), 0.01)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) InDelta(expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {\n\treturn InDelta(a.t, expected, actual, delta, msgAndArgs...)\n}\n\n// InEpsilon asserts that expected and actual have a relative error less than epsilon\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) InEpsilon(expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {\n\treturn InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...)\n}\n\n// NoError asserts that a function returned no error (i.e. `nil`).\n//\n//   actualObj, err := SomeFunction()\n//   if assert.NoError(err) {\n//\t   assert.Equal(actualObj, expectedObj)\n//   }\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) NoError(theError error, msgAndArgs ...interface{}) bool {\n\treturn NoError(a.t, theError, msgAndArgs...)\n}\n\n// Error asserts that a function returned an error (i.e. not `nil`).\n//\n//   actualObj, err := SomeFunction()\n//   if assert.Error(err, \"An error was expected\") {\n//\t   assert.Equal(err, expectedError)\n//   }\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Error(theError error, msgAndArgs ...interface{}) bool {\n\treturn Error(a.t, theError, msgAndArgs...)\n}\n\n// EqualError asserts that a function returned an error (i.e. not `nil`)\n// and that it is equal to the provided error.\n//\n//   actualObj, err := SomeFunction()\n//   if assert.Error(err, \"An error was expected\") {\n//\t   assert.Equal(err, expectedError)\n//   }\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) bool {\n\treturn EqualError(a.t, theError, errString, msgAndArgs...)\n}\n\n// Regexp asserts that a specified regexp matches a string.\n//\n//  assert.Regexp(t, regexp.MustCompile(\"start\"), \"it's starting\")\n//  assert.Regexp(t, \"start...$\", \"it's not starting\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Regexp(rx interface{}, str interface{}) bool {\n\treturn Regexp(a.t, rx, str)\n}\n\n// NotRegexp asserts that a specified regexp does not match a string.\n//\n//  assert.NotRegexp(t, regexp.MustCompile(\"starts\"), \"it's starting\")\n//  assert.NotRegexp(t, \"^start\", \"it's not starting\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) NotRegexp(rx interface{}, str interface{}) bool {\n\treturn NotRegexp(a.t, rx, str)\n}\n"
  },
  {
    "path": "vendor/github.com/stretchr/testify/assert/forward_assertions_test.go",
    "content": "package assert\n\nimport (\n\t\"errors\"\n\t\"regexp\"\n\t\"testing\"\n\t\"time\"\n)\n\nfunc TestImplementsWrapper(t *testing.T) {\n\tassert := New(new(testing.T))\n\n\tif !assert.Implements((*AssertionTesterInterface)(nil), new(AssertionTesterConformingObject)) {\n\t\tt.Error(\"Implements method should return true: AssertionTesterConformingObject implements AssertionTesterInterface\")\n\t}\n\tif assert.Implements((*AssertionTesterInterface)(nil), new(AssertionTesterNonConformingObject)) {\n\t\tt.Error(\"Implements method should return false: AssertionTesterNonConformingObject does not implements AssertionTesterInterface\")\n\t}\n}\n\nfunc TestIsTypeWrapper(t *testing.T) {\n\tassert := New(new(testing.T))\n\n\tif !assert.IsType(new(AssertionTesterConformingObject), new(AssertionTesterConformingObject)) {\n\t\tt.Error(\"IsType should return true: AssertionTesterConformingObject is the same type as AssertionTesterConformingObject\")\n\t}\n\tif assert.IsType(new(AssertionTesterConformingObject), new(AssertionTesterNonConformingObject)) {\n\t\tt.Error(\"IsType should return false: AssertionTesterConformingObject is not the same type as AssertionTesterNonConformingObject\")\n\t}\n\n}\n\nfunc TestEqualWrapper(t *testing.T) {\n\tassert := New(new(testing.T))\n\n\tif !assert.Equal(\"Hello World\", \"Hello World\") {\n\t\tt.Error(\"Equal should return true\")\n\t}\n\tif !assert.Equal(123, 123) {\n\t\tt.Error(\"Equal should return true\")\n\t}\n\tif !assert.Equal(123.5, 123.5) {\n\t\tt.Error(\"Equal should return true\")\n\t}\n\tif !assert.Equal([]byte(\"Hello World\"), []byte(\"Hello World\")) {\n\t\tt.Error(\"Equal should return true\")\n\t}\n\tif !assert.Equal(nil, nil) {\n\t\tt.Error(\"Equal should return true\")\n\t}\n}\n\nfunc TestNotNilWrapper(t *testing.T) {\n\tassert := New(new(testing.T))\n\n\tif !assert.NotNil(new(AssertionTesterConformingObject)) {\n\t\tt.Error(\"NotNil should return true: object is not nil\")\n\t}\n\tif assert.NotNil(nil) {\n\t\tt.Error(\"NotNil should return false: object is nil\")\n\t}\n\n}\n\nfunc TestNilWrapper(t *testing.T) {\n\tassert := New(new(testing.T))\n\n\tif !assert.Nil(nil) {\n\t\tt.Error(\"Nil should return true: object is nil\")\n\t}\n\tif assert.Nil(new(AssertionTesterConformingObject)) {\n\t\tt.Error(\"Nil should return false: object is not nil\")\n\t}\n\n}\n\nfunc TestTrueWrapper(t *testing.T) {\n\tassert := New(new(testing.T))\n\n\tif !assert.True(true) {\n\t\tt.Error(\"True should return true\")\n\t}\n\tif assert.True(false) {\n\t\tt.Error(\"True should return false\")\n\t}\n\n}\n\nfunc TestFalseWrapper(t *testing.T) {\n\tassert := New(new(testing.T))\n\n\tif !assert.False(false) {\n\t\tt.Error(\"False should return true\")\n\t}\n\tif assert.False(true) {\n\t\tt.Error(\"False should return false\")\n\t}\n\n}\n\nfunc TestExactlyWrapper(t *testing.T) {\n\tassert := New(new(testing.T))\n\n\ta := float32(1)\n\tb := float64(1)\n\tc := float32(1)\n\td := float32(2)\n\n\tif assert.Exactly(a, b) {\n\t\tt.Error(\"Exactly should return false\")\n\t}\n\tif assert.Exactly(a, d) {\n\t\tt.Error(\"Exactly should return false\")\n\t}\n\tif !assert.Exactly(a, c) {\n\t\tt.Error(\"Exactly should return true\")\n\t}\n\n\tif assert.Exactly(nil, a) {\n\t\tt.Error(\"Exactly should return false\")\n\t}\n\tif assert.Exactly(a, nil) {\n\t\tt.Error(\"Exactly should return false\")\n\t}\n\n}\n\nfunc TestNotEqualWrapper(t *testing.T) {\n\n\tassert := New(new(testing.T))\n\n\tif !assert.NotEqual(\"Hello World\", \"Hello World!\") {\n\t\tt.Error(\"NotEqual should return true\")\n\t}\n\tif !assert.NotEqual(123, 1234) {\n\t\tt.Error(\"NotEqual should return true\")\n\t}\n\tif !assert.NotEqual(123.5, 123.55) {\n\t\tt.Error(\"NotEqual should return true\")\n\t}\n\tif !assert.NotEqual([]byte(\"Hello World\"), []byte(\"Hello World!\")) {\n\t\tt.Error(\"NotEqual should return true\")\n\t}\n\tif !assert.NotEqual(nil, new(AssertionTesterConformingObject)) {\n\t\tt.Error(\"NotEqual should return true\")\n\t}\n}\n\nfunc TestContainsWrapper(t *testing.T) {\n\n\tassert := New(new(testing.T))\n\tlist := []string{\"Foo\", \"Bar\"}\n\n\tif !assert.Contains(\"Hello World\", \"Hello\") {\n\t\tt.Error(\"Contains should return true: \\\"Hello World\\\" contains \\\"Hello\\\"\")\n\t}\n\tif assert.Contains(\"Hello World\", \"Salut\") {\n\t\tt.Error(\"Contains should return false: \\\"Hello World\\\" does not contain \\\"Salut\\\"\")\n\t}\n\n\tif !assert.Contains(list, \"Foo\") {\n\t\tt.Error(\"Contains should return true: \\\"[\\\"Foo\\\", \\\"Bar\\\"]\\\" contains \\\"Foo\\\"\")\n\t}\n\tif assert.Contains(list, \"Salut\") {\n\t\tt.Error(\"Contains should return false: \\\"[\\\"Foo\\\", \\\"Bar\\\"]\\\" does not contain \\\"Salut\\\"\")\n\t}\n\n}\n\nfunc TestNotContainsWrapper(t *testing.T) {\n\n\tassert := New(new(testing.T))\n\tlist := []string{\"Foo\", \"Bar\"}\n\n\tif !assert.NotContains(\"Hello World\", \"Hello!\") {\n\t\tt.Error(\"NotContains should return true: \\\"Hello World\\\" does not contain \\\"Hello!\\\"\")\n\t}\n\tif assert.NotContains(\"Hello World\", \"Hello\") {\n\t\tt.Error(\"NotContains should return false: \\\"Hello World\\\" contains \\\"Hello\\\"\")\n\t}\n\n\tif !assert.NotContains(list, \"Foo!\") {\n\t\tt.Error(\"NotContains should return true: \\\"[\\\"Foo\\\", \\\"Bar\\\"]\\\" does not contain \\\"Foo!\\\"\")\n\t}\n\tif assert.NotContains(list, \"Foo\") {\n\t\tt.Error(\"NotContains should return false: \\\"[\\\"Foo\\\", \\\"Bar\\\"]\\\" contains \\\"Foo\\\"\")\n\t}\n\n}\n\nfunc TestConditionWrapper(t *testing.T) {\n\n\tassert := New(new(testing.T))\n\n\tif !assert.Condition(func() bool { return true }, \"Truth\") {\n\t\tt.Error(\"Condition should return true\")\n\t}\n\n\tif assert.Condition(func() bool { return false }, \"Lie\") {\n\t\tt.Error(\"Condition should return false\")\n\t}\n\n}\n\nfunc TestDidPanicWrapper(t *testing.T) {\n\n\tif funcDidPanic, _ := didPanic(func() {\n\t\tpanic(\"Panic!\")\n\t}); !funcDidPanic {\n\t\tt.Error(\"didPanic should return true\")\n\t}\n\n\tif funcDidPanic, _ := didPanic(func() {\n\t}); funcDidPanic {\n\t\tt.Error(\"didPanic should return false\")\n\t}\n\n}\n\nfunc TestPanicsWrapper(t *testing.T) {\n\n\tassert := New(new(testing.T))\n\n\tif !assert.Panics(func() {\n\t\tpanic(\"Panic!\")\n\t}) {\n\t\tt.Error(\"Panics should return true\")\n\t}\n\n\tif assert.Panics(func() {\n\t}) {\n\t\tt.Error(\"Panics should return false\")\n\t}\n\n}\n\nfunc TestNotPanicsWrapper(t *testing.T) {\n\n\tassert := New(new(testing.T))\n\n\tif !assert.NotPanics(func() {\n\t}) {\n\t\tt.Error(\"NotPanics should return true\")\n\t}\n\n\tif assert.NotPanics(func() {\n\t\tpanic(\"Panic!\")\n\t}) {\n\t\tt.Error(\"NotPanics should return false\")\n\t}\n\n}\n\nfunc TestEqualWrapper_Funcs(t *testing.T) {\n\n\tassert := New(t)\n\n\ttype f func() int\n\tvar f1 f = func() int { return 1 }\n\tvar f2 f = func() int { return 2 }\n\n\tvar f1_copy f = f1\n\n\tassert.Equal(f1_copy, f1, \"Funcs are the same and should be considered equal\")\n\tassert.NotEqual(f1, f2, \"f1 and f2 are different\")\n\n}\n\nfunc TestNoErrorWrapper(t *testing.T) {\n\tassert := New(t)\n\tmockAssert := New(new(testing.T))\n\n\t// start with a nil error\n\tvar err error = nil\n\n\tassert.True(mockAssert.NoError(err), \"NoError should return True for nil arg\")\n\n\t// now set an error\n\terr = errors.New(\"Some error\")\n\n\tassert.False(mockAssert.NoError(err), \"NoError with error should return False\")\n\n}\n\nfunc TestErrorWrapper(t *testing.T) {\n\tassert := New(t)\n\tmockAssert := New(new(testing.T))\n\n\t// start with a nil error\n\tvar err error = nil\n\n\tassert.False(mockAssert.Error(err), \"Error should return False for nil arg\")\n\n\t// now set an error\n\terr = errors.New(\"Some error\")\n\n\tassert.True(mockAssert.Error(err), \"Error with error should return True\")\n\n}\n\nfunc TestEqualErrorWrapper(t *testing.T) {\n\tassert := New(t)\n\tmockAssert := New(new(testing.T))\n\n\t// start with a nil error\n\tvar err error\n\tassert.False(mockAssert.EqualError(err, \"\"),\n\t\t\"EqualError should return false for nil arg\")\n\n\t// now set an error\n\terr = errors.New(\"some error\")\n\tassert.False(mockAssert.EqualError(err, \"Not some error\"),\n\t\t\"EqualError should return false for different error string\")\n\tassert.True(mockAssert.EqualError(err, \"some error\"),\n\t\t\"EqualError should return true\")\n}\n\nfunc TestEmptyWrapper(t *testing.T) {\n\tassert := New(t)\n\tmockAssert := New(new(testing.T))\n\n\tassert.True(mockAssert.Empty(\"\"), \"Empty string is empty\")\n\tassert.True(mockAssert.Empty(nil), \"Nil is empty\")\n\tassert.True(mockAssert.Empty([]string{}), \"Empty string array is empty\")\n\tassert.True(mockAssert.Empty(0), \"Zero int value is empty\")\n\tassert.True(mockAssert.Empty(false), \"False value is empty\")\n\n\tassert.False(mockAssert.Empty(\"something\"), \"Non Empty string is not empty\")\n\tassert.False(mockAssert.Empty(errors.New(\"something\")), \"Non nil object is not empty\")\n\tassert.False(mockAssert.Empty([]string{\"something\"}), \"Non empty string array is not empty\")\n\tassert.False(mockAssert.Empty(1), \"Non-zero int value is not empty\")\n\tassert.False(mockAssert.Empty(true), \"True value is not empty\")\n\n}\n\nfunc TestNotEmptyWrapper(t *testing.T) {\n\tassert := New(t)\n\tmockAssert := New(new(testing.T))\n\n\tassert.False(mockAssert.NotEmpty(\"\"), \"Empty string is empty\")\n\tassert.False(mockAssert.NotEmpty(nil), \"Nil is empty\")\n\tassert.False(mockAssert.NotEmpty([]string{}), \"Empty string array is empty\")\n\tassert.False(mockAssert.NotEmpty(0), \"Zero int value is empty\")\n\tassert.False(mockAssert.NotEmpty(false), \"False value is empty\")\n\n\tassert.True(mockAssert.NotEmpty(\"something\"), \"Non Empty string is not empty\")\n\tassert.True(mockAssert.NotEmpty(errors.New(\"something\")), \"Non nil object is not empty\")\n\tassert.True(mockAssert.NotEmpty([]string{\"something\"}), \"Non empty string array is not empty\")\n\tassert.True(mockAssert.NotEmpty(1), \"Non-zero int value is not empty\")\n\tassert.True(mockAssert.NotEmpty(true), \"True value is not empty\")\n\n}\n\nfunc TestLenWrapper(t *testing.T) {\n\tassert := New(t)\n\tmockAssert := New(new(testing.T))\n\n\tassert.False(mockAssert.Len(nil, 0), \"nil does not have length\")\n\tassert.False(mockAssert.Len(0, 0), \"int does not have length\")\n\tassert.False(mockAssert.Len(true, 0), \"true does not have length\")\n\tassert.False(mockAssert.Len(false, 0), \"false does not have length\")\n\tassert.False(mockAssert.Len('A', 0), \"Rune does not have length\")\n\tassert.False(mockAssert.Len(struct{}{}, 0), \"Struct does not have length\")\n\n\tch := make(chan int, 5)\n\tch <- 1\n\tch <- 2\n\tch <- 3\n\n\tcases := []struct {\n\t\tv interface{}\n\t\tl int\n\t}{\n\t\t{[]int{1, 2, 3}, 3},\n\t\t{[...]int{1, 2, 3}, 3},\n\t\t{\"ABC\", 3},\n\t\t{map[int]int{1: 2, 2: 4, 3: 6}, 3},\n\t\t{ch, 3},\n\n\t\t{[]int{}, 0},\n\t\t{map[int]int{}, 0},\n\t\t{make(chan int), 0},\n\n\t\t{[]int(nil), 0},\n\t\t{map[int]int(nil), 0},\n\t\t{(chan int)(nil), 0},\n\t}\n\n\tfor _, c := range cases {\n\t\tassert.True(mockAssert.Len(c.v, c.l), \"%#v have %d items\", c.v, c.l)\n\t}\n}\n\nfunc TestWithinDurationWrapper(t *testing.T) {\n\tassert := New(t)\n\tmockAssert := New(new(testing.T))\n\ta := time.Now()\n\tb := a.Add(10 * time.Second)\n\n\tassert.True(mockAssert.WithinDuration(a, b, 10*time.Second), \"A 10s difference is within a 10s time difference\")\n\tassert.True(mockAssert.WithinDuration(b, a, 10*time.Second), \"A 10s difference is within a 10s time difference\")\n\n\tassert.False(mockAssert.WithinDuration(a, b, 9*time.Second), \"A 10s difference is not within a 9s time difference\")\n\tassert.False(mockAssert.WithinDuration(b, a, 9*time.Second), \"A 10s difference is not within a 9s time difference\")\n\n\tassert.False(mockAssert.WithinDuration(a, b, -9*time.Second), \"A 10s difference is not within a 9s time difference\")\n\tassert.False(mockAssert.WithinDuration(b, a, -9*time.Second), \"A 10s difference is not within a 9s time difference\")\n\n\tassert.False(mockAssert.WithinDuration(a, b, -11*time.Second), \"A 10s difference is not within a 9s time difference\")\n\tassert.False(mockAssert.WithinDuration(b, a, -11*time.Second), \"A 10s difference is not within a 9s time difference\")\n}\n\nfunc TestInDeltaWrapper(t *testing.T) {\n\tassert := New(new(testing.T))\n\n\tTrue(t, assert.InDelta(1.001, 1, 0.01), \"|1.001 - 1| <= 0.01\")\n\tTrue(t, assert.InDelta(1, 1.001, 0.01), \"|1 - 1.001| <= 0.01\")\n\tTrue(t, assert.InDelta(1, 2, 1), \"|1 - 2| <= 1\")\n\tFalse(t, assert.InDelta(1, 2, 0.5), \"Expected |1 - 2| <= 0.5 to fail\")\n\tFalse(t, assert.InDelta(2, 1, 0.5), \"Expected |2 - 1| <= 0.5 to fail\")\n\tFalse(t, assert.InDelta(\"\", nil, 1), \"Expected non numerals to fail\")\n\n\tcases := []struct {\n\t\ta, b  interface{}\n\t\tdelta float64\n\t}{\n\t\t{uint8(2), uint8(1), 1},\n\t\t{uint16(2), uint16(1), 1},\n\t\t{uint32(2), uint32(1), 1},\n\t\t{uint64(2), uint64(1), 1},\n\n\t\t{int(2), int(1), 1},\n\t\t{int8(2), int8(1), 1},\n\t\t{int16(2), int16(1), 1},\n\t\t{int32(2), int32(1), 1},\n\t\t{int64(2), int64(1), 1},\n\n\t\t{float32(2), float32(1), 1},\n\t\t{float64(2), float64(1), 1},\n\t}\n\n\tfor _, tc := range cases {\n\t\tTrue(t, assert.InDelta(tc.a, tc.b, tc.delta), \"Expected |%V - %V| <= %v\", tc.a, tc.b, tc.delta)\n\t}\n}\n\nfunc TestInEpsilonWrapper(t *testing.T) {\n\tassert := New(new(testing.T))\n\n\tcases := []struct {\n\t\ta, b    interface{}\n\t\tepsilon float64\n\t}{\n\t\t{uint8(2), uint16(2), .001},\n\t\t{2.1, 2.2, 0.1},\n\t\t{2.2, 2.1, 0.1},\n\t\t{-2.1, -2.2, 0.1},\n\t\t{-2.2, -2.1, 0.1},\n\t\t{uint64(100), uint8(101), 0.01},\n\t\t{0.1, -0.1, 2},\n\t}\n\n\tfor _, tc := range cases {\n\t\tTrue(t, assert.InEpsilon(tc.a, tc.b, tc.epsilon, \"Expected %V and %V to have a relative difference of %v\", tc.a, tc.b, tc.epsilon))\n\t}\n\n\tcases = []struct {\n\t\ta, b    interface{}\n\t\tepsilon float64\n\t}{\n\t\t{uint8(2), int16(-2), .001},\n\t\t{uint64(100), uint8(102), 0.01},\n\t\t{2.1, 2.2, 0.001},\n\t\t{2.2, 2.1, 0.001},\n\t\t{2.1, -2.2, 1},\n\t\t{2.1, \"bla-bla\", 0},\n\t\t{0.1, -0.1, 1.99},\n\t}\n\n\tfor _, tc := range cases {\n\t\tFalse(t, assert.InEpsilon(tc.a, tc.b, tc.epsilon, \"Expected %V and %V to have a relative difference of %v\", tc.a, tc.b, tc.epsilon))\n\t}\n}\n\nfunc TestRegexpWrapper(t *testing.T) {\n\n\tassert := New(new(testing.T))\n\n\tcases := []struct {\n\t\trx, str string\n\t}{\n\t\t{\"^start\", \"start of the line\"},\n\t\t{\"end$\", \"in the end\"},\n\t\t{\"[0-9]{3}[.-]?[0-9]{2}[.-]?[0-9]{2}\", \"My phone number is 650.12.34\"},\n\t}\n\n\tfor _, tc := range cases {\n\t\tTrue(t, assert.Regexp(tc.rx, tc.str))\n\t\tTrue(t, assert.Regexp(regexp.MustCompile(tc.rx), tc.str))\n\t\tFalse(t, assert.NotRegexp(tc.rx, tc.str))\n\t\tFalse(t, assert.NotRegexp(regexp.MustCompile(tc.rx), tc.str))\n\t}\n\n\tcases = []struct {\n\t\trx, str string\n\t}{\n\t\t{\"^asdfastart\", \"Not the start of the line\"},\n\t\t{\"end$\", \"in the end.\"},\n\t\t{\"[0-9]{3}[.-]?[0-9]{2}[.-]?[0-9]{2}\", \"My phone number is 650.12a.34\"},\n\t}\n\n\tfor _, tc := range cases {\n\t\tFalse(t, assert.Regexp(tc.rx, tc.str), \"Expected \\\"%s\\\" to not match \\\"%s\\\"\", tc.rx, tc.str)\n\t\tFalse(t, assert.Regexp(regexp.MustCompile(tc.rx), tc.str))\n\t\tTrue(t, assert.NotRegexp(tc.rx, tc.str))\n\t\tTrue(t, assert.NotRegexp(regexp.MustCompile(tc.rx), tc.str))\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/stretchr/testify/assert/http_assertions.go",
    "content": "package assert\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"strings\"\n)\n\n// httpCode is a helper that returns HTTP code of the response. It returns -1\n// if building a new request fails.\nfunc httpCode(handler http.HandlerFunc, mode, url string, values url.Values) int {\n\tw := httptest.NewRecorder()\n\treq, err := http.NewRequest(mode, url+\"?\"+values.Encode(), nil)\n\tif err != nil {\n\t\treturn -1\n\t}\n\thandler(w, req)\n\treturn w.Code\n}\n\n// HTTPSuccess asserts that a specified handler returns a success status code.\n//\n//  assert.HTTPSuccess(t, myHandler, \"POST\", http://www.google.com\", nil)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc HTTPSuccess(t TestingT, handler http.HandlerFunc, mode, url string, values url.Values) bool {\n\tcode := httpCode(handler, mode, url, values)\n\tif code == -1 {\n\t\treturn false\n\t}\n\treturn code >= http.StatusOK && code <= http.StatusPartialContent\n}\n\n// HTTPRedirect asserts that a specified handler returns a redirect status code.\n//\n//  assert.HTTPRedirect(t, myHandler, \"GET\", \"/a/b/c\", url.Values{\"a\": []string{\"b\", \"c\"}}\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc HTTPRedirect(t TestingT, handler http.HandlerFunc, mode, url string, values url.Values) bool {\n\tcode := httpCode(handler, mode, url, values)\n\tif code == -1 {\n\t\treturn false\n\t}\n\treturn code >= http.StatusMultipleChoices && code <= http.StatusTemporaryRedirect\n}\n\n// HTTPError asserts that a specified handler returns an error status code.\n//\n//  assert.HTTPError(t, myHandler, \"POST\", \"/a/b/c\", url.Values{\"a\": []string{\"b\", \"c\"}}\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc HTTPError(t TestingT, handler http.HandlerFunc, mode, url string, values url.Values) bool {\n\tcode := httpCode(handler, mode, url, values)\n\tif code == -1 {\n\t\treturn false\n\t}\n\treturn code >= http.StatusBadRequest\n}\n\n// HttpBody is a helper that returns HTTP body of the response. It returns\n// empty string if building a new request fails.\nfunc HttpBody(handler http.HandlerFunc, mode, url string, values url.Values) string {\n\tw := httptest.NewRecorder()\n\treq, err := http.NewRequest(mode, url+\"?\"+values.Encode(), nil)\n\tif err != nil {\n\t\treturn \"\"\n\t}\n\thandler(w, req)\n\treturn w.Body.String()\n}\n\n// HTTPBodyContains asserts that a specified handler returns a\n// body that contains a string.\n//\n//  assert.HTTPBodyContains(t, myHandler, \"www.google.com\", nil, \"I'm Feeling Lucky\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc HTTPBodyContains(t TestingT, handler http.HandlerFunc, mode, url string, values url.Values, str interface{}) bool {\n\tbody := HttpBody(handler, mode, url, values)\n\n\tcontains := strings.Contains(body, fmt.Sprint(str))\n\tif !contains {\n\t\tFail(t, fmt.Sprintf(\"Expected response body for \\\"%s\\\" to contain \\\"%s\\\" but found \\\"%s\\\"\", url+\"?\"+values.Encode(), str, body))\n\t}\n\n\treturn contains\n}\n\n// HTTPBodyNotContains asserts that a specified handler returns a\n// body that does not contain a string.\n//\n//  assert.HTTPBodyNotContains(t, myHandler, \"www.google.com\", nil, \"I'm Feeling Lucky\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, mode, url string, values url.Values, str interface{}) bool {\n\tbody := HttpBody(handler, mode, url, values)\n\n\tcontains := strings.Contains(body, fmt.Sprint(str))\n\tif contains {\n\t\tFail(t, \"Expected response body for %s to NOT contain \\\"%s\\\" but found \\\"%s\\\"\", url+\"?\"+values.Encode(), str, body)\n\t}\n\n\treturn !contains\n}\n\n//\n// Assertions Wrappers\n//\n\n// HTTPSuccess asserts that a specified handler returns a success status code.\n//\n//  assert.HTTPSuccess(myHandler, \"POST\", http://www.google.com\", nil)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) HTTPSuccess(handler http.HandlerFunc, mode, url string, values url.Values) bool {\n\treturn HTTPSuccess(a.t, handler, mode, url, values)\n}\n\n// HTTPRedirect asserts that a specified handler returns a redirect status code.\n//\n//  assert.HTTPRedirect(myHandler, \"GET\", \"/a/b/c\", url.Values{\"a\": []string{\"b\", \"c\"}}\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) HTTPRedirect(handler http.HandlerFunc, mode, url string, values url.Values) bool {\n\treturn HTTPRedirect(a.t, handler, mode, url, values)\n}\n\n// HTTPError asserts that a specified handler returns an error status code.\n//\n//  assert.HTTPError(myHandler, \"POST\", \"/a/b/c\", url.Values{\"a\": []string{\"b\", \"c\"}}\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) HTTPError(handler http.HandlerFunc, mode, url string, values url.Values) bool {\n\treturn HTTPError(a.t, handler, mode, url, values)\n}\n\n// HTTPBodyContains asserts that a specified handler returns a\n// body that contains a string.\n//\n//  assert.HTTPBodyContains(t, myHandler, \"www.google.com\", nil, \"I'm Feeling Lucky\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, mode, url string, values url.Values, str interface{}) bool {\n\treturn HTTPBodyContains(a.t, handler, mode, url, values, str)\n}\n\n// HTTPBodyNotContains asserts that a specified handler returns a\n// body that does not contain a string.\n//\n//  assert.HTTPBodyNotContains(t, myHandler, \"www.google.com\", nil, \"I'm Feeling Lucky\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, mode, url string, values url.Values, str interface{}) bool {\n\treturn HTTPBodyNotContains(a.t, handler, mode, url, values, str)\n}\n"
  },
  {
    "path": "vendor/github.com/stretchr/testify/assert/http_assertions_test.go",
    "content": "package assert\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"testing\"\n)\n\nfunc httpOK(w http.ResponseWriter, r *http.Request) {\n\tw.WriteHeader(http.StatusOK)\n}\n\nfunc httpRedirect(w http.ResponseWriter, r *http.Request) {\n\tw.WriteHeader(http.StatusTemporaryRedirect)\n}\n\nfunc httpError(w http.ResponseWriter, r *http.Request) {\n\tw.WriteHeader(http.StatusInternalServerError)\n}\n\nfunc TestHTTPStatuses(t *testing.T) {\n\tassert := New(t)\n\tmockT := new(testing.T)\n\n\tassert.Equal(HTTPSuccess(mockT, httpOK, \"GET\", \"/\", nil), true)\n\tassert.Equal(HTTPSuccess(mockT, httpRedirect, \"GET\", \"/\", nil), false)\n\tassert.Equal(HTTPSuccess(mockT, httpError, \"GET\", \"/\", nil), false)\n\n\tassert.Equal(HTTPRedirect(mockT, httpOK, \"GET\", \"/\", nil), false)\n\tassert.Equal(HTTPRedirect(mockT, httpRedirect, \"GET\", \"/\", nil), true)\n\tassert.Equal(HTTPRedirect(mockT, httpError, \"GET\", \"/\", nil), false)\n\n\tassert.Equal(HTTPError(mockT, httpOK, \"GET\", \"/\", nil), false)\n\tassert.Equal(HTTPError(mockT, httpRedirect, \"GET\", \"/\", nil), false)\n\tassert.Equal(HTTPError(mockT, httpError, \"GET\", \"/\", nil), true)\n}\n\nfunc TestHTTPStatusesWrapper(t *testing.T) {\n\tassert := New(t)\n\tmockAssert := New(new(testing.T))\n\n\tassert.Equal(mockAssert.HTTPSuccess(httpOK, \"GET\", \"/\", nil), true)\n\tassert.Equal(mockAssert.HTTPSuccess(httpRedirect, \"GET\", \"/\", nil), false)\n\tassert.Equal(mockAssert.HTTPSuccess(httpError, \"GET\", \"/\", nil), false)\n\n\tassert.Equal(mockAssert.HTTPRedirect(httpOK, \"GET\", \"/\", nil), false)\n\tassert.Equal(mockAssert.HTTPRedirect(httpRedirect, \"GET\", \"/\", nil), true)\n\tassert.Equal(mockAssert.HTTPRedirect(httpError, \"GET\", \"/\", nil), false)\n\n\tassert.Equal(mockAssert.HTTPError(httpOK, \"GET\", \"/\", nil), false)\n\tassert.Equal(mockAssert.HTTPError(httpRedirect, \"GET\", \"/\", nil), false)\n\tassert.Equal(mockAssert.HTTPError(httpError, \"GET\", \"/\", nil), true)\n}\n\nfunc httpHelloName(w http.ResponseWriter, r *http.Request) {\n\tname := r.FormValue(\"name\")\n\tw.Write([]byte(fmt.Sprintf(\"Hello, %s!\", name)))\n}\n\nfunc TestHttpBody(t *testing.T) {\n\tassert := New(t)\n\tmockT := new(testing.T)\n\n\tassert.True(HTTPBodyContains(mockT, httpHelloName, \"GET\", \"/\", url.Values{\"name\": []string{\"World\"}}, \"Hello, World!\"))\n\tassert.True(HTTPBodyContains(mockT, httpHelloName, \"GET\", \"/\", url.Values{\"name\": []string{\"World\"}}, \"World\"))\n\tassert.False(HTTPBodyContains(mockT, httpHelloName, \"GET\", \"/\", url.Values{\"name\": []string{\"World\"}}, \"world\"))\n\n\tassert.False(HTTPBodyNotContains(mockT, httpHelloName, \"GET\", \"/\", url.Values{\"name\": []string{\"World\"}}, \"Hello, World!\"))\n\tassert.False(HTTPBodyNotContains(mockT, httpHelloName, \"GET\", \"/\", url.Values{\"name\": []string{\"World\"}}, \"World\"))\n\tassert.True(HTTPBodyNotContains(mockT, httpHelloName, \"GET\", \"/\", url.Values{\"name\": []string{\"World\"}}, \"world\"))\n}\n\nfunc TestHttpBodyWrappers(t *testing.T) {\n\tassert := New(t)\n\tmockAssert := New(new(testing.T))\n\n\tassert.True(mockAssert.HTTPBodyContains(httpHelloName, \"GET\", \"/\", url.Values{\"name\": []string{\"World\"}}, \"Hello, World!\"))\n\tassert.True(mockAssert.HTTPBodyContains(httpHelloName, \"GET\", \"/\", url.Values{\"name\": []string{\"World\"}}, \"World\"))\n\tassert.False(mockAssert.HTTPBodyContains(httpHelloName, \"GET\", \"/\", url.Values{\"name\": []string{\"World\"}}, \"world\"))\n\n\tassert.False(mockAssert.HTTPBodyNotContains(httpHelloName, \"GET\", \"/\", url.Values{\"name\": []string{\"World\"}}, \"Hello, World!\"))\n\tassert.False(mockAssert.HTTPBodyNotContains(httpHelloName, \"GET\", \"/\", url.Values{\"name\": []string{\"World\"}}, \"World\"))\n\tassert.True(mockAssert.HTTPBodyNotContains(httpHelloName, \"GET\", \"/\", url.Values{\"name\": []string{\"World\"}}, \"world\"))\n\n}\n"
  },
  {
    "path": "vendor/github.com/stretchr/testify/require/doc.go",
    "content": "// Alternative testing tools which stop test execution if test failed.\n//\n// Example Usage\n//\n// The following is a complete example using require in a standard test function:\n//    import (\n//      \"testing\"\n//      \"github.com/stretchr/testify/require\"\n//    )\n//\n//    func TestSomething(t *testing.T) {\n//\n//      var a string = \"Hello\"\n//      var b string = \"Hello\"\n//\n//      require.Equal(t, a, b, \"The two words should be the same.\")\n//\n//    }\n//\n// Assertions\n//\n// The `require` package have same global functions as in the `assert` package,\n// but instead of returning a boolean result they call `t.FailNow()`.\n//\n// Every assertion function also takes an optional string message as the final argument,\n// allowing custom error messages to be appended to the message the assertion method outputs.\n//\n// Here is an overview of the assert functions:\n//\n//    require.Equal(t, expected, actual [, message [, format-args])\n//\n//    require.NotEqual(t, notExpected, actual [, message [, format-args]])\n//\n//    require.True(t, actualBool [, message [, format-args]])\n//\n//    require.False(t, actualBool [, message [, format-args]])\n//\n//    require.Nil(t, actualObject [, message [, format-args]])\n//\n//    require.NotNil(t, actualObject [, message [, format-args]])\n//\n//    require.Empty(t, actualObject [, message [, format-args]])\n//\n//    require.NotEmpty(t, actualObject [, message [, format-args]])\n//\n//    require.Error(t, errorObject [, message [, format-args]])\n//\n//    require.NoError(t, errorObject [, message [, format-args]])\n//\n//    require.EqualError(t, theError, errString [, message [, format-args]])\n//\n//    require.Implements(t, (*MyInterface)(nil), new(MyObject) [,message [, format-args]])\n//\n//    require.IsType(t, expectedObject, actualObject [, message [, format-args]])\n//\n//    require.Contains(t, string, substring [, message [, format-args]])\n//\n//    require.NotContains(t, string, substring [, message [, format-args]])\n//\n//    require.Panics(t, func(){\n//\n//\t    // call code that should panic\n//\n//    } [, message [, format-args]])\n//\n//    require.NotPanics(t, func(){\n//\n//\t    // call code that should not panic\n//\n//    } [, message [, format-args]])\n//\n//    require.WithinDuration(t, timeA, timeB, deltaTime, [, message [, format-args]])\n//\n//    require.InDelta(t, numA, numB, delta, [, message [, format-args]])\n//\n//    require.InEpsilon(t, numA, numB, epsilon, [, message [, format-args]])\npackage require\n"
  },
  {
    "path": "vendor/github.com/stretchr/testify/require/requirements.go",
    "content": "package require\n\nimport (\n\t\"github.com/stretchr/testify/assert\"\n\t\"time\"\n)\n\ntype TestingT interface {\n\tErrorf(format string, args ...interface{})\n\tFailNow()\n}\n\n// Fail reports a failure through\nfunc FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) {\n\tassert.Fail(t, failureMessage, msgAndArgs...)\n\tt.FailNow()\n}\n\n// Implements asserts that an object is implemented by the specified interface.\n//\n//    require.Implements(t, (*MyInterface)(nil), new(MyObject), \"MyObject\")\nfunc Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) {\n\tif !assert.Implements(t, interfaceObject, object, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// IsType asserts that the specified objects are of the same type.\nfunc IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) {\n\tif !assert.IsType(t, expectedType, object, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// Equal asserts that two objects are equal.\n//\n//    require.Equal(t, 123, 123, \"123 and 123 should be equal\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) {\n\tif !assert.Equal(t, expected, actual, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// Exactly asserts that two objects are equal is value and type.\n//\n//    require.Exactly(t, int32(123), int64(123), \"123 and 123 should NOT be equal\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) {\n\tif !assert.Exactly(t, expected, actual, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// NotNil asserts that the specified object is not nil.\n//\n//    require.NotNil(t, err, \"err should be something\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) {\n\tif !assert.NotNil(t, object, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// Nil asserts that the specified object is nil.\n//\n//    require.Nil(t, err, \"err should be nothing\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) {\n\tif !assert.Nil(t, object, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// Empty asserts that the specified object is empty.  I.e. nil, \"\", false, 0 or either\n// a slice or a channel with len == 0.\n//\n// require.Empty(t, obj)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) {\n\tif !assert.Empty(t, object, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// NotEmpty asserts that the specified object is NOT empty.  I.e. not nil, \"\", false, 0 or either\n// a slice or a channel with len == 0.\n//\n// require.NotEmpty(t, obj)\n// require.Equal(t, \"one\", obj[0])\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) {\n\tif !assert.NotEmpty(t, object, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// True asserts that the specified value is true.\n//\n//    require.True(t, myBool, \"myBool should be true\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc True(t TestingT, value bool, msgAndArgs ...interface{}) {\n\tif !assert.True(t, value, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// False asserts that the specified value is true.\n//\n//    require.False(t, myBool, \"myBool should be false\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc False(t TestingT, value bool, msgAndArgs ...interface{}) {\n\tif !assert.False(t, value, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// NotEqual asserts that the specified values are NOT equal.\n//\n//    require.NotEqual(t, obj1, obj2, \"two objects shouldn't be equal\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) {\n\tif !assert.NotEqual(t, expected, actual, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// Contains asserts that the specified string contains the specified substring.\n//\n//    require.Contains(t, \"Hello World\", \"World\", \"But 'Hello World' does contain 'World'\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Contains(t TestingT, s, contains string, msgAndArgs ...interface{}) {\n\tif !assert.Contains(t, s, contains, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// NotContains asserts that the specified string does NOT contain the specified substring.\n//\n//    require.NotContains(t, \"Hello World\", \"Earth\", \"But 'Hello World' does NOT contain 'Earth'\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc NotContains(t TestingT, s, contains string, msgAndArgs ...interface{}) {\n\tif !assert.NotContains(t, s, contains, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// Condition uses a Comparison to assert a complex condition.\nfunc Condition(t TestingT, comp assert.Comparison, msgAndArgs ...interface{}) {\n\tif !assert.Condition(t, comp, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// Panics asserts that the code inside the specified PanicTestFunc panics.\n//\n//   require.Panics(t, func(){\n//     GoCrazy()\n//   }, \"Calling GoCrazy() should panic\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Panics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) {\n\tif !assert.Panics(t, f, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.\n//\n//   require.NotPanics(t, func(){\n//     RemainCalm()\n//   }, \"Calling RemainCalm() should NOT panic\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc NotPanics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) {\n\tif !assert.NotPanics(t, f, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// WithinDuration asserts that the two times are within duration delta of each other.\n//\n//   require.WithinDuration(t, time.Now(), time.Now(), 10*time.Second, \"The difference should not be more than 10s\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc WithinDuration(t TestingT, expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) {\n\tif !assert.WithinDuration(t, expected, actual, delta, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// InDelta asserts that the two numerals are within delta of each other.\n//\n//   require.InDelta(t, math.Pi, (22 / 7.0), 0.01)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc InDelta(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) {\n\tif !assert.InDelta(t, expected, actual, delta, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// InEpsilon asserts that expected and actual have a relative error less than epsilon\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc InEpsilon(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {\n\tif !assert.InEpsilon(t, expected, actual, epsilon, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n/*\n\tErrors\n*/\n\n// NoError asserts that a function returned no error (i.e. `nil`).\n//\n//   actualObj, err := SomeFunction()\n//   require.NoError(t, err)\n//   require.Equal(t, actualObj, expectedObj)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc NoError(t TestingT, err error, msgAndArgs ...interface{}) {\n\tif !assert.NoError(t, err, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// Error asserts that a function returned an error (i.e. not `nil`).\n//\n//   actualObj, err := SomeFunction()\n//   require.Error(t, err, \"An error was expected\")\n//   require.Equal(t, err, expectedError)\n//   }\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Error(t TestingT, err error, msgAndArgs ...interface{}) {\n\tif !assert.Error(t, err, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// EqualError asserts that a function returned an error (i.e. not `nil`)\n// and that it is equal to the provided error.\n//\n//   actualObj, err := SomeFunction()\n//   require.Error(t, err, \"An error was expected\")\n//   require.Equal(t, err, expectedError)\n//   }\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) {\n\tif !assert.EqualError(t, theError, errString, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/stretchr/testify/require/requirements_test.go",
    "content": "package require\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\t\"time\"\n)\n\n// AssertionTesterInterface defines an interface to be used for testing assertion methods\ntype AssertionTesterInterface interface {\n\tTestMethod()\n}\n\n// AssertionTesterConformingObject is an object that conforms to the AssertionTesterInterface interface\ntype AssertionTesterConformingObject struct {\n}\n\nfunc (a *AssertionTesterConformingObject) TestMethod() {\n}\n\n// AssertionTesterNonConformingObject is an object that does not conform to the AssertionTesterInterface interface\ntype AssertionTesterNonConformingObject struct {\n}\n\ntype MockT struct {\n\tFailed bool\n}\n\nfunc (t *MockT) FailNow() {\n\tt.Failed = true\n}\n\nfunc (t *MockT) Errorf(format string, args ...interface{}) {\n\t_, _ = format, args\n}\n\nfunc TestImplements(t *testing.T) {\n\n\tImplements(t, (*AssertionTesterInterface)(nil), new(AssertionTesterConformingObject))\n\n\tmockT := new(MockT)\n\tImplements(mockT, (*AssertionTesterInterface)(nil), new(AssertionTesterNonConformingObject))\n\tif !mockT.Failed {\n\t\tt.Error(\"Check should fail\")\n\t}\n}\n\nfunc TestIsType(t *testing.T) {\n\n\tIsType(t, new(AssertionTesterConformingObject), new(AssertionTesterConformingObject))\n\n\tmockT := new(MockT)\n\tIsType(mockT, new(AssertionTesterConformingObject), new(AssertionTesterNonConformingObject))\n\tif !mockT.Failed {\n\t\tt.Error(\"Check should fail\")\n\t}\n}\n\nfunc TestEqual(t *testing.T) {\n\n\tEqual(t, 1, 1)\n\n\tmockT := new(MockT)\n\tEqual(mockT, 1, 2)\n\tif !mockT.Failed {\n\t\tt.Error(\"Check should fail\")\n\t}\n\n}\n\nfunc TestNotEqual(t *testing.T) {\n\n\tNotEqual(t, 1, 2)\n\tmockT := new(MockT)\n\tNotEqual(mockT, 2, 2)\n\tif !mockT.Failed {\n\t\tt.Error(\"Check should fail\")\n\t}\n}\n\nfunc TestExactly(t *testing.T) {\n\n\ta := float32(1)\n\tb := float32(1)\n\tc := float64(1)\n\n\tExactly(t, a, b)\n\n\tmockT := new(MockT)\n\tExactly(mockT, a, c)\n\tif !mockT.Failed {\n\t\tt.Error(\"Check should fail\")\n\t}\n}\n\nfunc TestNotNil(t *testing.T) {\n\n\tNotNil(t, new(AssertionTesterConformingObject))\n\n\tmockT := new(MockT)\n\tNotNil(mockT, nil)\n\tif !mockT.Failed {\n\t\tt.Error(\"Check should fail\")\n\t}\n}\n\nfunc TestNil(t *testing.T) {\n\n\tNil(t, nil)\n\n\tmockT := new(MockT)\n\tNil(mockT, new(AssertionTesterConformingObject))\n\tif !mockT.Failed {\n\t\tt.Error(\"Check should fail\")\n\t}\n}\n\nfunc TestTrue(t *testing.T) {\n\n\tTrue(t, true)\n\n\tmockT := new(MockT)\n\tTrue(mockT, false)\n\tif !mockT.Failed {\n\t\tt.Error(\"Check should fail\")\n\t}\n}\n\nfunc TestFalse(t *testing.T) {\n\n\tFalse(t, false)\n\n\tmockT := new(MockT)\n\tFalse(mockT, true)\n\tif !mockT.Failed {\n\t\tt.Error(\"Check should fail\")\n\t}\n}\n\nfunc TestContains(t *testing.T) {\n\n\tContains(t, \"Hello World\", \"Hello\")\n\n\tmockT := new(MockT)\n\tContains(mockT, \"Hello World\", \"Salut\")\n\tif !mockT.Failed {\n\t\tt.Error(\"Check should fail\")\n\t}\n}\n\nfunc TestNotContains(t *testing.T) {\n\n\tNotContains(t, \"Hello World\", \"Hello!\")\n\n\tmockT := new(MockT)\n\tNotContains(mockT, \"Hello World\", \"Hello\")\n\tif !mockT.Failed {\n\t\tt.Error(\"Check should fail\")\n\t}\n}\n\nfunc TestPanics(t *testing.T) {\n\n\tPanics(t, func() {\n\t\tpanic(\"Panic!\")\n\t})\n\n\tmockT := new(MockT)\n\tPanics(mockT, func() {})\n\tif !mockT.Failed {\n\t\tt.Error(\"Check should fail\")\n\t}\n}\n\nfunc TestNotPanics(t *testing.T) {\n\n\tNotPanics(t, func() {})\n\n\tmockT := new(MockT)\n\tNotPanics(mockT, func() {\n\t\tpanic(\"Panic!\")\n\t})\n\tif !mockT.Failed {\n\t\tt.Error(\"Check should fail\")\n\t}\n}\n\nfunc TestNoError(t *testing.T) {\n\n\tNoError(t, nil)\n\n\tmockT := new(MockT)\n\tNoError(mockT, errors.New(\"some error\"))\n\tif !mockT.Failed {\n\t\tt.Error(\"Check should fail\")\n\t}\n}\n\nfunc TestError(t *testing.T) {\n\n\tError(t, errors.New(\"some error\"))\n\n\tmockT := new(MockT)\n\tError(mockT, nil)\n\tif !mockT.Failed {\n\t\tt.Error(\"Check should fail\")\n\t}\n}\n\nfunc TestEqualError(t *testing.T) {\n\n\tEqualError(t, errors.New(\"some error\"), \"some error\")\n\n\tmockT := new(MockT)\n\tEqualError(mockT, errors.New(\"some error\"), \"Not some error\")\n\tif !mockT.Failed {\n\t\tt.Error(\"Check should fail\")\n\t}\n}\n\nfunc TestEmpty(t *testing.T) {\n\n\tEmpty(t, \"\")\n\n\tmockT := new(MockT)\n\tEmpty(mockT, \"x\")\n\tif !mockT.Failed {\n\t\tt.Error(\"Check should fail\")\n\t}\n}\n\nfunc TestNotEmpty(t *testing.T) {\n\n\tNotEmpty(t, \"x\")\n\n\tmockT := new(MockT)\n\tNotEmpty(mockT, \"\")\n\tif !mockT.Failed {\n\t\tt.Error(\"Check should fail\")\n\t}\n}\n\nfunc TestWithinDuration(t *testing.T) {\n\n\ta := time.Now()\n\tb := a.Add(10 * time.Second)\n\n\tWithinDuration(t, a, b, 15*time.Second)\n\n\tmockT := new(MockT)\n\tWithinDuration(mockT, a, b, 5*time.Second)\n\tif !mockT.Failed {\n\t\tt.Error(\"Check should fail\")\n\t}\n}\n\nfunc TestInDelta(t *testing.T) {\n\n\tInDelta(t, 1.001, 1, 0.01)\n\n\tmockT := new(MockT)\n\tInDelta(mockT, 1, 2, 0.5)\n\tif !mockT.Failed {\n\t\tt.Error(\"Check should fail\")\n\t}\n}\n"
  },
  {
    "path": "vendor/gopkg.in/djherbis/stream.v1/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015 Dustin H\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "vendor/gopkg.in/djherbis/stream.v1/README.md",
    "content": "stream \n==========\n\n[![GoDoc](https://godoc.org/github.com/djherbis/stream?status.svg)](https://godoc.org/github.com/djherbis/stream)\n[![Release](https://img.shields.io/github/release/djherbis/stream.svg)](https://github.com/djherbis/stream/releases/latest)\n[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](LICENSE.txt)\n[![Build Status](https://travis-ci.org/djherbis/stream.svg?branch=master)](https://travis-ci.org/djherbis/stream)\n[![Coverage Status](https://coveralls.io/repos/djherbis/stream/badge.svg?branch=master)](https://coveralls.io/r/djherbis/stream?branch=master)\n\nUsage\n------------\n\nWrite and Read concurrently, and independently.\n\nTo explain further, if you need to write to multiple places you can use io.MultiWriter,\nif you need multiple Readers on something you can use io.TeeReader. If you want concurrency you can use io.Pipe(). \n\nHowever all of these methods \"tie\" each Read/Write together, your readers can't read from different places in the stream, each write must be distributed to all readers in sequence. \n\nThis package provides a way for multiple Readers to read off the same Writer, without waiting for the others. This is done by writing to a \"File\" interface which buffers the input so it can be read at any time from many independent readers. Readers can even be created while writing or after the stream is closed. They will all see a consistent view of the stream and will block until the section of the stream they request is written, all while being unaffected by the actions of the other readers.\n\nThe use case for this stems from my other project djherbis/fscache. I needed a byte caching mechanism which allowed many independent clients to have access to the data while it was being written, rather than re-generating the byte stream for each of them or waiting for a complete copy of the stream which could be stored and then re-used.\n\n```go\nimport(\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/djherbis/stream\"\n)\n\nfunc main(){\n\tw, err := stream.New(\"mystream\")\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\tgo func(){\n\t\tio.WriteString(w, \"Hello World!\")\n\t\t<-time.After(time.Second)\n\t\tio.WriteString(w, \"Streaming updates...\")\n\t\tw.Close()\n\t}()\n\n\twaitForReader := make(chan struct{})\n\tgo func(){\n\t\t// Read from the stream\n\t\tr, err := w.NextReader()\n\t\tif err != nil {\n\t\t\tlog.Fatal(err)\n\t\t}\n\t\tio.Copy(os.Stdout, r) // Hello World! (1 second) Streaming updates...\n\t\tr.Close()\n\t\tclose(waitForReader)\n\t}()\n\n  // Full copy of the stream!\n\tr, err := w.NextReader() \n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tio.Copy(os.Stdout, r) // Hello World! (1 second) Streaming updates...\n\n\t// r supports io.ReaderAt too.\n\tp := make([]byte, 4)\n\tr.ReadAt(p, 1) // Read \"ello\" into p\n\n\tr.Close()\n\n\t<-waitForReader // don't leave main before go-routine finishes\n}\n```\n\nInstallation\n------------\n```sh\ngo get github.com/djherbis/stream\n```\n"
  },
  {
    "path": "vendor/gopkg.in/djherbis/stream.v1/fs.go",
    "content": "package stream\n\nimport (\n\t\"io\"\n\t\"os\"\n)\n\n// File is a backing data-source for a Stream.\ntype File interface {\n\tName() string // The name used to Create/Open the File\n\tio.Reader     // Reader must continue reading after EOF on subsequent calls after more Writes.\n\tio.ReaderAt   // Similarly to Reader\n\tio.Writer     // Concurrent reading/writing must be supported.\n\tio.Closer     // Close should do any cleanup when done with the File.\n}\n\n// FileSystem is used to manage Files\ntype FileSystem interface {\n\tCreate(name string) (File, error) // Create must return a new File for Writing\n\tOpen(name string) (File, error)   // Open must return an existing File for Reading\n\tRemove(name string) error         // Remove deletes an existing File\n}\n\n// StdFileSystem is backed by the os package.\nvar StdFileSystem FileSystem = stdFS{}\n\ntype stdFS struct{}\n\nfunc (fs stdFS) Create(name string) (File, error) {\n\treturn os.Create(name)\n}\n\nfunc (fs stdFS) Open(name string) (File, error) {\n\treturn os.Open(name)\n}\n\nfunc (fs stdFS) Remove(name string) error {\n\treturn os.Remove(name)\n}\n"
  },
  {
    "path": "vendor/gopkg.in/djherbis/stream.v1/memfs.go",
    "content": "package stream\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"io\"\n\t\"sync\"\n)\n\n// ErrNotFoundInMem is returned when an in-memory FileSystem cannot find a file.\nvar ErrNotFoundInMem = errors.New(\"not found\")\n\ntype memfs struct {\n\tmu    sync.RWMutex\n\tfiles map[string]*memFile\n}\n\n// NewMemFS returns a New in-memory FileSystem\nfunc NewMemFS() FileSystem {\n\treturn &memfs{\n\t\tfiles: make(map[string]*memFile),\n\t}\n}\n\nfunc (fs *memfs) Create(key string) (File, error) {\n\tfs.mu.Lock()\n\tdefer fs.mu.Unlock()\n\n\tfile := &memFile{\n\t\tname: key,\n\t\tr:    bytes.NewBuffer(nil),\n\t}\n\tfile.memReader.memFile = file\n\tfs.files[key] = file\n\treturn file, nil\n}\n\nfunc (fs *memfs) Open(key string) (File, error) {\n\tfs.mu.RLock()\n\tdefer fs.mu.RUnlock()\n\n\tif f, ok := fs.files[key]; ok {\n\t\treturn &memReader{memFile: f}, nil\n\t}\n\treturn nil, ErrNotFoundInMem\n}\n\nfunc (fs *memfs) Remove(key string) error {\n\tfs.mu.Lock()\n\tdefer fs.mu.Unlock()\n\tdelete(fs.files, key)\n\treturn nil\n}\n\ntype memFile struct {\n\tmu   sync.RWMutex\n\tname string\n\tr    *bytes.Buffer\n\tmemReader\n}\n\nfunc (f *memFile) Name() string {\n\treturn f.name\n}\n\nfunc (f *memFile) Write(p []byte) (int, error) {\n\tif len(p) > 0 {\n\t\tf.mu.Lock()\n\t\tdefer f.mu.Unlock()\n\t\treturn f.r.Write(p)\n\t}\n\treturn len(p), nil\n}\n\nfunc (f *memFile) Bytes() []byte {\n\tf.mu.RLock()\n\tdefer f.mu.RUnlock()\n\treturn f.r.Bytes()\n}\n\nfunc (f *memFile) Close() error {\n\treturn nil\n}\n\ntype memReader struct {\n\t*memFile\n\tn int\n}\n\nfunc (r *memReader) ReadAt(p []byte, off int64) (n int, err error) {\n\tdata := r.Bytes()\n\tif int64(len(data)) < off {\n\t\treturn 0, io.EOF\n\t}\n\tn, err = bytes.NewReader(data[off:]).ReadAt(p, 0)\n\treturn n, err\n}\n\nfunc (r *memReader) Read(p []byte) (n int, err error) {\n\tn, err = bytes.NewReader(r.Bytes()[r.n:]).Read(p)\n\tr.n += n\n\treturn n, err\n}\n\nfunc (r *memReader) Close() error {\n\treturn nil\n}\n"
  },
  {
    "path": "vendor/gopkg.in/djherbis/stream.v1/reader.go",
    "content": "package stream\n\nimport \"io\"\n\n// Reader is a concurrent-safe Stream Reader.\ntype Reader struct {\n\ts    *Stream\n\tfile File\n}\n\n// Name returns the name of the underlying File in the FileSystem.\nfunc (r *Reader) Name() string { return r.file.Name() }\n\n// ReadAt lets you Read from specific offsets in the Stream.\n// ReadAt blocks while waiting for the requested section of the Stream to be written,\n// unless the Stream is closed in which case it will always return immediately.\nfunc (r *Reader) ReadAt(p []byte, off int64) (n int, err error) {\n\tr.s.b.RLock()\n\tdefer r.s.b.RUnlock()\n\n\tvar m int\n\n\tfor {\n\n\t\tm, err = r.file.ReadAt(p[n:], off+int64(n))\n\t\tn += m\n\n\t\tif r.s.b.IsOpen() {\n\n\t\t\tswitch {\n\t\t\tcase n != 0 && err == nil:\n\t\t\t\treturn n, err\n\t\t\tcase err == io.EOF:\n\t\t\t\tr.s.b.Wait()\n\t\t\tcase err != nil:\n\t\t\t\treturn n, err\n\t\t\t}\n\n\t\t} else {\n\t\t\treturn n, err\n\t\t}\n\n\t}\n}\n\n// Read reads from the Stream. If the end of an open Stream is reached, Read\n// blocks until more data is written or the Stream is Closed.\nfunc (r *Reader) Read(p []byte) (n int, err error) {\n\tr.s.b.RLock()\n\tdefer r.s.b.RUnlock()\n\n\tvar m int\n\n\tfor {\n\n\t\tm, err = r.file.Read(p[n:])\n\t\tn += m\n\n\t\tif r.s.b.IsOpen() {\n\n\t\t\tswitch {\n\t\t\tcase n != 0 && err == nil:\n\t\t\t\treturn n, err\n\t\t\tcase err == io.EOF:\n\t\t\t\tr.s.b.Wait()\n\t\t\tcase err != nil:\n\t\t\t\treturn n, err\n\t\t\t}\n\n\t\t} else {\n\t\t\treturn n, err\n\t\t}\n\n\t}\n}\n\n// Close closes this Reader on the Stream. This must be called when done with the\n// Reader or else the Stream cannot be Removed.\nfunc (r *Reader) Close() error {\n\tdefer r.s.dec()\n\treturn r.file.Close()\n}\n"
  },
  {
    "path": "vendor/gopkg.in/djherbis/stream.v1/stream.go",
    "content": "// Package stream provides a way to read and write to a synchronous buffered pipe, with multiple reader support.\npackage stream\n\nimport (\n\t\"errors\"\n\t\"sync\"\n)\n\n// ErrRemoving is returned when requesting a Reader on a Stream which is being Removed.\nvar ErrRemoving = errors.New(\"cannot open a new reader while removing file\")\n\n// Stream is used to concurrently Write and Read from a File.\ntype Stream struct {\n\tgrp      sync.WaitGroup\n\tb        *broadcaster\n\tfile     File\n\tfs       FileSystem\n\tremoving chan struct{}\n}\n\n// New creates a new Stream from the StdFileSystem with Name \"name\".\nfunc New(name string) (*Stream, error) {\n\treturn NewStream(name, StdFileSystem)\n}\n\n// NewStream creates a new Stream with Name \"name\" in FileSystem fs.\nfunc NewStream(name string, fs FileSystem) (*Stream, error) {\n\tf, err := fs.Create(name)\n\tsf := &Stream{\n\t\tfile:     f,\n\t\tfs:       fs,\n\t\tb:        newBroadcaster(),\n\t\tremoving: make(chan struct{}),\n\t}\n\tsf.inc()\n\treturn sf, err\n}\n\n// Name returns the name of the underlying File in the FileSystem.\nfunc (s *Stream) Name() string { return s.file.Name() }\n\n// Write writes p to the Stream. It's concurrent safe to be called with Stream's other methods.\nfunc (s *Stream) Write(p []byte) (int, error) {\n\tdefer s.b.Broadcast()\n\ts.b.Lock()\n\tdefer s.b.Unlock()\n\treturn s.file.Write(p)\n}\n\n// Close will close the active stream. This will cause Readers to return EOF once they have\n// read the entire stream.\nfunc (s *Stream) Close() error {\n\tdefer s.dec()\n\tdefer s.b.Close()\n\ts.b.Lock()\n\tdefer s.b.Unlock()\n\treturn s.file.Close()\n}\n\n// Remove will block until the Stream and all its Readers have been Closed,\n// at which point it will delete the underlying file. NextReader() will return\n// ErrRemoving if called after Remove.\nfunc (s *Stream) Remove() error {\n\tclose(s.removing)\n\ts.grp.Wait()\n\treturn s.fs.Remove(s.file.Name())\n}\n\n// NextReader will return a concurrent-safe Reader for this stream. Each Reader will\n// see a complete and independent view of the stream, and can Read will the stream\n// is written to.\nfunc (s *Stream) NextReader() (*Reader, error) {\n\ts.inc()\n\n\tselect {\n\tcase <-s.removing:\n\t\ts.dec()\n\t\treturn nil, ErrRemoving\n\tdefault:\n\t}\n\n\tfile, err := s.fs.Open(s.file.Name())\n\tif err != nil {\n\t\ts.dec()\n\t\treturn nil, err\n\t}\n\n\treturn &Reader{file: file, s: s}, nil\n}\n\nfunc (s *Stream) inc() { s.grp.Add(1) }\nfunc (s *Stream) dec() { s.grp.Done() }\n"
  },
  {
    "path": "vendor/gopkg.in/djherbis/stream.v1/stream_test.go",
    "content": "package stream\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"io\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n)\n\nvar (\n\ttestdata = []byte(\"hello\\nworld\\n\")\n\terrFail  = errors.New(\"fail\")\n)\n\ntype badFs struct {\n\treaders []File\n}\ntype badFile struct{ name string }\n\nfunc (r badFile) Name() string                            { return r.name }\nfunc (r badFile) Read(p []byte) (int, error)              { return 0, errFail }\nfunc (r badFile) ReadAt(p []byte, off int64) (int, error) { return 0, errFail }\nfunc (r badFile) Write(p []byte) (int, error)             { return 0, errFail }\nfunc (r badFile) Close() error                            { return errFail }\n\nfunc (fs badFs) Create(name string) (File, error) { return os.Create(name) }\nfunc (fs badFs) Open(name string) (File, error) {\n\tif len(fs.readers) > 0 {\n\t\tf := fs.readers[len(fs.readers)-1]\n\t\tfs.readers = fs.readers[:len(fs.readers)-1]\n\t\treturn f, nil\n\t}\n\treturn nil, errFail\n}\nfunc (fs badFs) Remove(name string) error { return os.Remove(name) }\n\nfunc TestMemFs(t *testing.T) {\n\tfs := NewMemFS()\n\tif _, err := fs.Open(\"not found\"); err != ErrNotFoundInMem {\n\t\tt.Error(err)\n\t\tt.FailNow()\n\t}\n}\n\nfunc TestBadFile(t *testing.T) {\n\tfs := badFs{readers: make([]File, 0, 1)}\n\tfs.readers = append(fs.readers, badFile{name: \"test\"})\n\tf, err := NewStream(\"test\", fs)\n\tif err != nil {\n\t\tt.Error(err)\n\t\tt.FailNow()\n\t}\n\tdefer f.Remove()\n\tdefer f.Close()\n\n\tr, err := f.NextReader()\n\tif err != nil {\n\t\tt.Error(err)\n\t\tt.FailNow()\n\t}\n\tdefer r.Close()\n\tif r.Name() != \"test\" {\n\t\tt.Errorf(\"expected name to to be 'test' got %s\", r.Name())\n\t\tt.FailNow()\n\t}\n\tif _, err := r.ReadAt(nil, 0); err == nil {\n\t\tt.Error(\"expected ReadAt error\")\n\t\tt.FailNow()\n\t}\n\tif _, err := r.Read(nil); err == nil {\n\t\tt.Error(\"expected Read error\")\n\t\tt.FailNow()\n\t}\n}\n\nfunc TestBadFs(t *testing.T) {\n\tf, err := NewStream(\"test\", badFs{})\n\tif err != nil {\n\t\tt.Error(err)\n\t\tt.FailNow()\n\t}\n\tdefer f.Remove()\n\tdefer f.Close()\n\n\tr, err := f.NextReader()\n\tif err == nil {\n\t\tt.Error(\"expected open error\")\n\t\tt.FailNow()\n\t} else {\n\t\treturn\n\t}\n\tr.Close()\n}\n\nfunc TestStd(t *testing.T) {\n\tf, err := New(\"test.txt\")\n\tif err != nil {\n\t\tt.Error(err)\n\t\tt.FailNow()\n\t}\n\tif f.Name() != \"test.txt\" {\n\t\tt.Errorf(\"expected name to be test.txt: %s\", f.Name())\n\t}\n\ttestFile(f, t)\n}\n\nfunc TestMem(t *testing.T) {\n\tf, err := NewStream(\"test.txt\", NewMemFS())\n\tif err != nil {\n\t\tt.Error(err)\n\t\tt.FailNow()\n\t}\n\tf.Write(nil)\n\ttestFile(f, t)\n}\n\nfunc TestRemove(t *testing.T) {\n\tf, err := NewStream(\"test.txt\", NewMemFS())\n\tif err != nil {\n\t\tt.Error(err)\n\t\tt.FailNow()\n\t}\n\tdefer f.Close()\n\tgo f.Remove()\n\t<-time.After(100 * time.Millisecond)\n\tr, err := f.NextReader()\n\tswitch err {\n\tcase ErrRemoving:\n\tcase nil:\n\t\tt.Error(\"expected error on NextReader()\")\n\t\tr.Close()\n\tdefault:\n\t\tt.Error(\"expected diff error on NextReader()\", err)\n\t}\n\n}\n\nfunc testFile(f *Stream, t *testing.T) {\n\n\tfor i := 0; i < 10; i++ {\n\t\tgo testReader(f, t)\n\t}\n\n\tfor i := 0; i < 10; i++ {\n\t\tf.Write(testdata)\n\t\t<-time.After(10 * time.Millisecond)\n\t}\n\n\tf.Close()\n\ttestReader(f, t)\n\tf.Remove()\n}\n\nfunc testReader(f *Stream, t *testing.T) {\n\tr, err := f.NextReader()\n\tif err != nil {\n\t\tt.Error(err)\n\t\tt.FailNow()\n\t}\n\tdefer r.Close()\n\n\tbuf := bytes.NewBuffer(nil)\n\tsr := io.NewSectionReader(r, 1+int64(len(testdata)*5), 5)\n\tio.Copy(buf, sr)\n\tif !bytes.Equal(buf.Bytes(), testdata[1:6]) {\n\t\tt.Errorf(\"unequal %s\", buf.Bytes())\n\t\treturn\n\t}\n\n\tbuf.Reset()\n\tio.Copy(buf, r)\n\tif !bytes.Equal(buf.Bytes(), bytes.Repeat(testdata, 10)) {\n\t\tt.Errorf(\"unequal %s\", buf.Bytes())\n\t\treturn\n\t}\n}\n"
  },
  {
    "path": "vendor/gopkg.in/djherbis/stream.v1/sync.go",
    "content": "package stream\n\nimport (\n\t\"sync\"\n\t\"sync/atomic\"\n)\n\ntype broadcaster struct {\n\tsync.RWMutex\n\tclosed uint32\n\t*sync.Cond\n}\n\nfunc newBroadcaster() *broadcaster {\n\tvar b broadcaster\n\tb.Cond = sync.NewCond(b.RWMutex.RLocker())\n\treturn &b\n}\n\nfunc (b *broadcaster) Wait() {\n\tif b.IsOpen() {\n\t\tb.Cond.Wait()\n\t}\n}\n\nfunc (b *broadcaster) IsOpen() bool {\n\treturn atomic.LoadUint32(&b.closed) == 0\n}\n\nfunc (b *broadcaster) Close() error {\n\tatomic.StoreUint32(&b.closed, 1)\n\tb.Cond.Broadcast()\n\treturn nil\n}\n"
  },
  {
    "path": "vendor/vendor.json",
    "content": "{\n\t\"comment\": \"\",\n\t\"ignore\": \"\",\n\t\"package\": [\n\t\t{\n\t\t\t\"checksumSHA1\": \"uz5IFOxRG/odXyNSLahNaQmRfTw=\",\n\t\t\t\"path\": \"github.com/rainycape/vfs\",\n\t\t\t\"revision\": \"a62fd22bcf7010946a44f6a1250a82c03110a14b\",\n\t\t\t\"revisionTime\": \"2015-06-11T13:38:00Z\"\n\t\t},\n\t\t{\n\t\t\t\"checksumSHA1\": \"l0Y/7HWT3FyVZDag6I+nPvklh0g=\",\n\t\t\t\"path\": \"github.com/stretchr/testify/assert\",\n\t\t\t\"revision\": \"de7fcff264cd05cc0c90c509ea789a436a0dd206\",\n\t\t\t\"revisionTime\": \"2014-09-15T02:00:11Z\"\n\t\t},\n\t\t{\n\t\t\t\"checksumSHA1\": \"AFPcO/L4YHgqiLJb1hMFvwBI59M=\",\n\t\t\t\"path\": \"github.com/stretchr/testify/require\",\n\t\t\t\"revision\": \"de7fcff264cd05cc0c90c509ea789a436a0dd206\",\n\t\t\t\"revisionTime\": \"2014-09-15T02:00:11Z\"\n\t\t},\n\t\t{\n\t\t\t\"checksumSHA1\": \"r2P3nttwhwKuAdSecDkyU+t2d/s=\",\n\t\t\t\"path\": \"gopkg.in/djherbis/stream.v1\",\n\t\t\t\"revision\": \"26a761059928627ca84837000dfb33447c66a146\",\n\t\t\t\"revisionTime\": \"2016-02-04T06:24:40Z\"\n\t\t}\n\t],\n\t\"rootPath\": \"github.com/lox/httpcache\"\n}\n"
  },
  {
    "path": "wercker.yml",
    "content": "# https://registry.hub.docker.com/u/library/golang/\nbox: golang\nbuild:\n  steps:\n    - setup-go-workspace\n    - script:\n        name: go test\n        code: |\n          go test . ./cli/... ./httplog/...\n"
  }
]