diff --git a/go.sum b/go.sum
index fba59e59f..90ba32db0 100644
--- a/go.sum
+++ b/go.sum
@@ -501,6 +501,7 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190328211700-ab21143f2384 h1:TFlARGu6Czu1z7q93HTxcP1P+/ZFC/IKythI5RzrnRg=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
diff --git a/vendor/github.com/OneOfOne/xxhash/.gitignore b/vendor/github.com/OneOfOne/xxhash/.gitignore
new file mode 100644
index 000000000..f4faa7f8f
--- /dev/null
+++ b/vendor/github.com/OneOfOne/xxhash/.gitignore
@@ -0,0 +1,4 @@
+*.txt
+*.pprof
+cmap2/
+cache/
diff --git a/vendor/github.com/OneOfOne/xxhash/.travis.yml b/vendor/github.com/OneOfOne/xxhash/.travis.yml
new file mode 100644
index 000000000..1c6dc55bc
--- /dev/null
+++ b/vendor/github.com/OneOfOne/xxhash/.travis.yml
@@ -0,0 +1,13 @@
+language: go
+sudo: false
+
+go:
+ - "1.10"
+ - "1.11"
+ - "1.12"
+ - master
+
+script:
+ - go test -tags safe ./...
+ - go test ./...
+ -
diff --git a/vendor/github.com/OneOfOne/xxhash/LICENSE b/vendor/github.com/OneOfOne/xxhash/LICENSE
new file mode 100644
index 000000000..9e30b4f34
--- /dev/null
+++ b/vendor/github.com/OneOfOne/xxhash/LICENSE
@@ -0,0 +1,187 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "{}"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
diff --git a/vendor/github.com/OneOfOne/xxhash/README.md b/vendor/github.com/OneOfOne/xxhash/README.md
new file mode 100644
index 000000000..23174eb56
--- /dev/null
+++ b/vendor/github.com/OneOfOne/xxhash/README.md
@@ -0,0 +1,75 @@
+# xxhash [](https://godoc.org/github.com/OneOfOne/xxhash) [](https://travis-ci.org/OneOfOne/xxhash) [](https://gocover.io/github.com/OneOfOne/xxhash)
+
+This is a native Go implementation of the excellent [xxhash](https://github.com/Cyan4973/xxHash)* algorithm, an extremely fast non-cryptographic Hash algorithm, working at speeds close to RAM limits.
+
+* The C implementation is ([Copyright](https://github.com/Cyan4973/xxHash/blob/master/LICENSE) (c) 2012-2014, Yann Collet)
+
+## Install
+
+ go get github.com/OneOfOne/xxhash
+
+## Features
+
+* On Go 1.7+ the pure go version is faster than CGO for all inputs.
+* Supports ChecksumString{32,64} xxhash{32,64}.WriteString, which uses no copies when it can, falls back to copy on appengine.
+* The native version falls back to a less optimized version on appengine due to the lack of unsafe.
+* Almost as fast as the mostly pure assembly version written by the brilliant [cespare](https://github.com/cespare/xxhash), while also supporting seeds.
+* To manually toggle the appengine version build with `-tags safe`.
+
+## Benchmark
+
+### Core i7-4790 @ 3.60GHz, Linux 4.12.6-1-ARCH (64bit), Go tip (+ff90f4af66 2017-08-19)
+
+```bash
+➤ go test -bench '64' -count 5 -tags cespare | benchstat /dev/stdin
+name time/op
+
+# https://github.com/cespare/xxhash
+XXSum64Cespare/Func-8 160ns ± 2%
+XXSum64Cespare/Struct-8 173ns ± 1%
+XXSum64ShortCespare/Func-8 6.78ns ± 1%
+XXSum64ShortCespare/Struct-8 19.6ns ± 2%
+
+# this package (default mode, using unsafe)
+XXSum64/Func-8 170ns ± 1%
+XXSum64/Struct-8 182ns ± 1%
+XXSum64Short/Func-8 13.5ns ± 3%
+XXSum64Short/Struct-8 20.4ns ± 0%
+
+# this package (appengine, *not* using unsafe)
+XXSum64/Func-8 241ns ± 5%
+XXSum64/Struct-8 243ns ± 6%
+XXSum64Short/Func-8 15.2ns ± 2%
+XXSum64Short/Struct-8 23.7ns ± 5%
+
+CRC64ISO-8 1.23µs ± 1%
+CRC64ISOString-8 2.71µs ± 4%
+CRC64ISOShort-8 22.2ns ± 3%
+
+Fnv64-8 2.34µs ± 1%
+Fnv64Short-8 74.7ns ± 8%
+#
+```
+
+## Usage
+
+```go
+ h := xxhash.New64()
+ // r, err := os.Open("......")
+ // defer f.Close()
+ r := strings.NewReader(F)
+ io.Copy(h, r)
+ fmt.Println("xxhash.Backend:", xxhash.Backend)
+ fmt.Println("File checksum:", h.Sum64())
+```
+
+[playground](http://play.golang.org/p/rhRN3RdQyd)
+
+## TODO
+
+* Rewrite the 32bit version to be more optimized.
+* General cleanup as the Go inliner gets smarter.
+
+## License
+
+This project is released under the Apache v2. licence. See [LICENCE](LICENCE) for more details.
diff --git a/vendor/github.com/OneOfOne/xxhash/go.mod b/vendor/github.com/OneOfOne/xxhash/go.mod
new file mode 100644
index 000000000..c6da85e0a
--- /dev/null
+++ b/vendor/github.com/OneOfOne/xxhash/go.mod
@@ -0,0 +1,3 @@
+module github.com/OneOfOne/xxhash
+
+go 1.11
diff --git a/vendor/github.com/OneOfOne/xxhash/xxhash.go b/vendor/github.com/OneOfOne/xxhash/xxhash.go
new file mode 100644
index 000000000..2387d6593
--- /dev/null
+++ b/vendor/github.com/OneOfOne/xxhash/xxhash.go
@@ -0,0 +1,189 @@
+package xxhash
+
+const (
+ prime32x1 uint32 = 2654435761
+ prime32x2 uint32 = 2246822519
+ prime32x3 uint32 = 3266489917
+ prime32x4 uint32 = 668265263
+ prime32x5 uint32 = 374761393
+
+ prime64x1 uint64 = 11400714785074694791
+ prime64x2 uint64 = 14029467366897019727
+ prime64x3 uint64 = 1609587929392839161
+ prime64x4 uint64 = 9650029242287828579
+ prime64x5 uint64 = 2870177450012600261
+
+ maxInt32 int32 = (1<<31 - 1)
+
+ // precomputed zero Vs for seed 0
+ zero64x1 = 0x60ea27eeadc0b5d6
+ zero64x2 = 0xc2b2ae3d27d4eb4f
+ zero64x3 = 0x0
+ zero64x4 = 0x61c8864e7a143579
+)
+
+// Checksum32 returns the checksum of the input data with the seed set to 0.
+func Checksum32(in []byte) uint32 {
+ return Checksum32S(in, 0)
+}
+
+// ChecksumString32 returns the checksum of the input data, without creating a copy, with the seed set to 0.
+func ChecksumString32(s string) uint32 {
+ return ChecksumString32S(s, 0)
+}
+
+type XXHash32 struct {
+ mem [16]byte
+ ln, memIdx int32
+ v1, v2, v3, v4 uint32
+ seed uint32
+}
+
+// Size returns the number of bytes Sum will return.
+func (xx *XXHash32) Size() int {
+ return 4
+}
+
+// BlockSize returns the hash's underlying block size.
+// The Write method must be able to accept any amount
+// of data, but it may operate more efficiently if all writes
+// are a multiple of the block size.
+func (xx *XXHash32) BlockSize() int {
+ return 16
+}
+
+// NewS32 creates a new hash.Hash32 computing the 32bit xxHash checksum starting with the specific seed.
+func NewS32(seed uint32) (xx *XXHash32) {
+ xx = &XXHash32{
+ seed: seed,
+ }
+ xx.Reset()
+ return
+}
+
+// New32 creates a new hash.Hash32 computing the 32bit xxHash checksum starting with the seed set to 0.
+func New32() *XXHash32 {
+ return NewS32(0)
+}
+
+func (xx *XXHash32) Reset() {
+ xx.v1 = xx.seed + prime32x1 + prime32x2
+ xx.v2 = xx.seed + prime32x2
+ xx.v3 = xx.seed
+ xx.v4 = xx.seed - prime32x1
+ xx.ln, xx.memIdx = 0, 0
+}
+
+// Sum appends the current hash to b and returns the resulting slice.
+// It does not change the underlying hash state.
+func (xx *XXHash32) Sum(in []byte) []byte {
+ s := xx.Sum32()
+ return append(in, byte(s>>24), byte(s>>16), byte(s>>8), byte(s))
+}
+
+// Checksum64 an alias for Checksum64S(in, 0)
+func Checksum64(in []byte) uint64 {
+ return Checksum64S(in, 0)
+}
+
+// ChecksumString64 returns the checksum of the input data, without creating a copy, with the seed set to 0.
+func ChecksumString64(s string) uint64 {
+ return ChecksumString64S(s, 0)
+}
+
+type XXHash64 struct {
+ v1, v2, v3, v4 uint64
+ seed uint64
+ ln uint64
+ mem [32]byte
+ memIdx int8
+}
+
+// Size returns the number of bytes Sum will return.
+func (xx *XXHash64) Size() int {
+ return 8
+}
+
+// BlockSize returns the hash's underlying block size.
+// The Write method must be able to accept any amount
+// of data, but it may operate more efficiently if all writes
+// are a multiple of the block size.
+func (xx *XXHash64) BlockSize() int {
+ return 32
+}
+
+// NewS64 creates a new hash.Hash64 computing the 64bit xxHash checksum starting with the specific seed.
+func NewS64(seed uint64) (xx *XXHash64) {
+ xx = &XXHash64{
+ seed: seed,
+ }
+ xx.Reset()
+ return
+}
+
+// New64 creates a new hash.Hash64 computing the 64bit xxHash checksum starting with the seed set to 0x0.
+func New64() *XXHash64 {
+ return NewS64(0)
+}
+
+func (xx *XXHash64) Reset() {
+ xx.ln, xx.memIdx = 0, 0
+ xx.v1, xx.v2, xx.v3, xx.v4 = resetVs64(xx.seed)
+}
+
+// Sum appends the current hash to b and returns the resulting slice.
+// It does not change the underlying hash state.
+func (xx *XXHash64) Sum(in []byte) []byte {
+ s := xx.Sum64()
+ return append(in, byte(s>>56), byte(s>>48), byte(s>>40), byte(s>>32), byte(s>>24), byte(s>>16), byte(s>>8), byte(s))
+}
+
+// force the compiler to use ROTL instructions
+
+func rotl32_1(x uint32) uint32 { return (x << 1) | (x >> (32 - 1)) }
+func rotl32_7(x uint32) uint32 { return (x << 7) | (x >> (32 - 7)) }
+func rotl32_11(x uint32) uint32 { return (x << 11) | (x >> (32 - 11)) }
+func rotl32_12(x uint32) uint32 { return (x << 12) | (x >> (32 - 12)) }
+func rotl32_13(x uint32) uint32 { return (x << 13) | (x >> (32 - 13)) }
+func rotl32_17(x uint32) uint32 { return (x << 17) | (x >> (32 - 17)) }
+func rotl32_18(x uint32) uint32 { return (x << 18) | (x >> (32 - 18)) }
+
+func rotl64_1(x uint64) uint64 { return (x << 1) | (x >> (64 - 1)) }
+func rotl64_7(x uint64) uint64 { return (x << 7) | (x >> (64 - 7)) }
+func rotl64_11(x uint64) uint64 { return (x << 11) | (x >> (64 - 11)) }
+func rotl64_12(x uint64) uint64 { return (x << 12) | (x >> (64 - 12)) }
+func rotl64_18(x uint64) uint64 { return (x << 18) | (x >> (64 - 18)) }
+func rotl64_23(x uint64) uint64 { return (x << 23) | (x >> (64 - 23)) }
+func rotl64_27(x uint64) uint64 { return (x << 27) | (x >> (64 - 27)) }
+func rotl64_31(x uint64) uint64 { return (x << 31) | (x >> (64 - 31)) }
+
+func mix64(h uint64) uint64 {
+ h ^= h >> 33
+ h *= prime64x2
+ h ^= h >> 29
+ h *= prime64x3
+ h ^= h >> 32
+ return h
+}
+
+func resetVs64(seed uint64) (v1, v2, v3, v4 uint64) {
+ if seed == 0 {
+ return zero64x1, zero64x2, zero64x3, zero64x4
+ }
+ return (seed + prime64x1 + prime64x2), (seed + prime64x2), (seed), (seed - prime64x1)
+}
+
+// borrowed from cespare
+func round64(h, v uint64) uint64 {
+ h += v * prime64x2
+ h = rotl64_31(h)
+ h *= prime64x1
+ return h
+}
+
+func mergeRound64(h, v uint64) uint64 {
+ v = round64(0, v)
+ h ^= v
+ h = h*prime64x1 + prime64x4
+ return h
+}
diff --git a/vendor/github.com/OneOfOne/xxhash/xxhash_go17.go b/vendor/github.com/OneOfOne/xxhash/xxhash_go17.go
new file mode 100644
index 000000000..ae48e0c5c
--- /dev/null
+++ b/vendor/github.com/OneOfOne/xxhash/xxhash_go17.go
@@ -0,0 +1,161 @@
+package xxhash
+
+func u32(in []byte) uint32 {
+ return uint32(in[0]) | uint32(in[1])<<8 | uint32(in[2])<<16 | uint32(in[3])<<24
+}
+
+func u64(in []byte) uint64 {
+ return uint64(in[0]) | uint64(in[1])<<8 | uint64(in[2])<<16 | uint64(in[3])<<24 | uint64(in[4])<<32 | uint64(in[5])<<40 | uint64(in[6])<<48 | uint64(in[7])<<56
+}
+
+// Checksum32S returns the checksum of the input bytes with the specific seed.
+func Checksum32S(in []byte, seed uint32) (h uint32) {
+ var i int
+
+ if len(in) > 15 {
+ var (
+ v1 = seed + prime32x1 + prime32x2
+ v2 = seed + prime32x2
+ v3 = seed + 0
+ v4 = seed - prime32x1
+ )
+ for ; i < len(in)-15; i += 16 {
+ in := in[i : i+16 : len(in)]
+ v1 += u32(in[0:4:len(in)]) * prime32x2
+ v1 = rotl32_13(v1) * prime32x1
+
+ v2 += u32(in[4:8:len(in)]) * prime32x2
+ v2 = rotl32_13(v2) * prime32x1
+
+ v3 += u32(in[8:12:len(in)]) * prime32x2
+ v3 = rotl32_13(v3) * prime32x1
+
+ v4 += u32(in[12:16:len(in)]) * prime32x2
+ v4 = rotl32_13(v4) * prime32x1
+ }
+
+ h = rotl32_1(v1) + rotl32_7(v2) + rotl32_12(v3) + rotl32_18(v4)
+
+ } else {
+ h = seed + prime32x5
+ }
+
+ h += uint32(len(in))
+ for ; i <= len(in)-4; i += 4 {
+ in := in[i : i+4 : len(in)]
+ h += u32(in[0:4:len(in)]) * prime32x3
+ h = rotl32_17(h) * prime32x4
+ }
+
+ for ; i < len(in); i++ {
+ h += uint32(in[i]) * prime32x5
+ h = rotl32_11(h) * prime32x1
+ }
+
+ h ^= h >> 15
+ h *= prime32x2
+ h ^= h >> 13
+ h *= prime32x3
+ h ^= h >> 16
+
+ return
+}
+
+func (xx *XXHash32) Write(in []byte) (n int, err error) {
+ i, ml := 0, int(xx.memIdx)
+ n = len(in)
+ xx.ln += int32(n)
+
+ if d := 16 - ml; ml > 0 && ml+len(in) > 16 {
+ xx.memIdx += int32(copy(xx.mem[xx.memIdx:], in[:d]))
+ ml, in = 16, in[d:len(in):len(in)]
+ } else if ml+len(in) < 16 {
+ xx.memIdx += int32(copy(xx.mem[xx.memIdx:], in))
+ return
+ }
+
+ if ml > 0 {
+ i += 16 - ml
+ xx.memIdx += int32(copy(xx.mem[xx.memIdx:len(xx.mem):len(xx.mem)], in))
+ in := xx.mem[:16:len(xx.mem)]
+
+ xx.v1 += u32(in[0:4:len(in)]) * prime32x2
+ xx.v1 = rotl32_13(xx.v1) * prime32x1
+
+ xx.v2 += u32(in[4:8:len(in)]) * prime32x2
+ xx.v2 = rotl32_13(xx.v2) * prime32x1
+
+ xx.v3 += u32(in[8:12:len(in)]) * prime32x2
+ xx.v3 = rotl32_13(xx.v3) * prime32x1
+
+ xx.v4 += u32(in[12:16:len(in)]) * prime32x2
+ xx.v4 = rotl32_13(xx.v4) * prime32x1
+
+ xx.memIdx = 0
+ }
+
+ for ; i <= len(in)-16; i += 16 {
+ in := in[i : i+16 : len(in)]
+ xx.v1 += u32(in[0:4:len(in)]) * prime32x2
+ xx.v1 = rotl32_13(xx.v1) * prime32x1
+
+ xx.v2 += u32(in[4:8:len(in)]) * prime32x2
+ xx.v2 = rotl32_13(xx.v2) * prime32x1
+
+ xx.v3 += u32(in[8:12:len(in)]) * prime32x2
+ xx.v3 = rotl32_13(xx.v3) * prime32x1
+
+ xx.v4 += u32(in[12:16:len(in)]) * prime32x2
+ xx.v4 = rotl32_13(xx.v4) * prime32x1
+ }
+
+ if len(in)-i != 0 {
+ xx.memIdx += int32(copy(xx.mem[xx.memIdx:], in[i:len(in):len(in)]))
+ }
+
+ return
+}
+
+func (xx *XXHash32) Sum32() (h uint32) {
+ var i int32
+ if xx.ln > 15 {
+ h = rotl32_1(xx.v1) + rotl32_7(xx.v2) + rotl32_12(xx.v3) + rotl32_18(xx.v4)
+ } else {
+ h = xx.seed + prime32x5
+ }
+
+ h += uint32(xx.ln)
+
+ if xx.memIdx > 0 {
+ for ; i < xx.memIdx-3; i += 4 {
+ in := xx.mem[i : i+4 : len(xx.mem)]
+ h += u32(in[0:4:len(in)]) * prime32x3
+ h = rotl32_17(h) * prime32x4
+ }
+
+ for ; i < xx.memIdx; i++ {
+ h += uint32(xx.mem[i]) * prime32x5
+ h = rotl32_11(h) * prime32x1
+ }
+ }
+ h ^= h >> 15
+ h *= prime32x2
+ h ^= h >> 13
+ h *= prime32x3
+ h ^= h >> 16
+
+ return
+}
+
+// Checksum64S returns the 64bit xxhash checksum for a single input
+func Checksum64S(in []byte, seed uint64) uint64 {
+ if len(in) == 0 && seed == 0 {
+ return 0xef46db3751d8e999
+ }
+
+ if len(in) > 31 {
+ return checksum64(in, seed)
+ }
+
+ return checksum64Short(in, seed)
+}
diff --git a/vendor/github.com/OneOfOne/xxhash/xxhash_safe.go b/vendor/github.com/OneOfOne/xxhash/xxhash_safe.go
new file mode 100644
index 000000000..e92ec29e0
--- /dev/null
+++ b/vendor/github.com/OneOfOne/xxhash/xxhash_safe.go
@@ -0,0 +1,183 @@
+// +build appengine safe ppc64le ppc64be mipsle mips s390x
+
+package xxhash
+
+// Backend returns the current version of xxhash being used.
+const Backend = "GoSafe"
+
+func ChecksumString32S(s string, seed uint32) uint32 {
+ return Checksum32S([]byte(s), seed)
+}
+
+func (xx *XXHash32) WriteString(s string) (int, error) {
+ if len(s) == 0 {
+ return 0, nil
+ }
+ return xx.Write([]byte(s))
+}
+
+func ChecksumString64S(s string, seed uint64) uint64 {
+ return Checksum64S([]byte(s), seed)
+}
+
+func (xx *XXHash64) WriteString(s string) (int, error) {
+ if len(s) == 0 {
+ return 0, nil
+ }
+ return xx.Write([]byte(s))
+}
+
+func checksum64(in []byte, seed uint64) (h uint64) {
+ var (
+ v1, v2, v3, v4 = resetVs64(seed)
+
+ i int
+ )
+
+ for ; i < len(in)-31; i += 32 {
+ in := in[i : i+32 : len(in)]
+ v1 = round64(v1, u64(in[0:8:len(in)]))
+ v2 = round64(v2, u64(in[8:16:len(in)]))
+ v3 = round64(v3, u64(in[16:24:len(in)]))
+ v4 = round64(v4, u64(in[24:32:len(in)]))
+ }
+
+ h = rotl64_1(v1) + rotl64_7(v2) + rotl64_12(v3) + rotl64_18(v4)
+
+ h = mergeRound64(h, v1)
+ h = mergeRound64(h, v2)
+ h = mergeRound64(h, v3)
+ h = mergeRound64(h, v4)
+
+ h += uint64(len(in))
+
+ for ; i < len(in)-7; i += 8 {
+ h ^= round64(0, u64(in[i:len(in):len(in)]))
+ h = rotl64_27(h)*prime64x1 + prime64x4
+ }
+
+ for ; i < len(in)-3; i += 4 {
+ h ^= uint64(u32(in[i:len(in):len(in)])) * prime64x1
+ h = rotl64_23(h)*prime64x2 + prime64x3
+ }
+
+ for ; i < len(in); i++ {
+ h ^= uint64(in[i]) * prime64x5
+ h = rotl64_11(h) * prime64x1
+ }
+
+ return mix64(h)
+}
+
+func checksum64Short(in []byte, seed uint64) uint64 {
+ var (
+ h = seed + prime64x5 + uint64(len(in))
+ i int
+ )
+
+ for ; i < len(in)-7; i += 8 {
+ k := u64(in[i : i+8 : len(in)])
+ h ^= round64(0, k)
+ h = rotl64_27(h)*prime64x1 + prime64x4
+ }
+
+ for ; i < len(in)-3; i += 4 {
+ h ^= uint64(u32(in[i:i+4:len(in)])) * prime64x1
+ h = rotl64_23(h)*prime64x2 + prime64x3
+ }
+
+ for ; i < len(in); i++ {
+ h ^= uint64(in[i]) * prime64x5
+ h = rotl64_11(h) * prime64x1
+ }
+
+ return mix64(h)
+}
+
+func (xx *XXHash64) Write(in []byte) (n int, err error) {
+ var (
+ ml = int(xx.memIdx)
+ d = 32 - ml
+ )
+
+ n = len(in)
+ xx.ln += uint64(n)
+
+ if ml+len(in) < 32 {
+ xx.memIdx += int8(copy(xx.mem[xx.memIdx:len(xx.mem):len(xx.mem)], in))
+ return
+ }
+
+ i, v1, v2, v3, v4 := 0, xx.v1, xx.v2, xx.v3, xx.v4
+ if ml > 0 && ml+len(in) > 32 {
+ xx.memIdx += int8(copy(xx.mem[xx.memIdx:len(xx.mem):len(xx.mem)], in[:d:len(in)]))
+ in = in[d:len(in):len(in)]
+
+ in := xx.mem[0:32:len(xx.mem)]
+
+ v1 = round64(v1, u64(in[0:8:len(in)]))
+ v2 = round64(v2, u64(in[8:16:len(in)]))
+ v3 = round64(v3, u64(in[16:24:len(in)]))
+ v4 = round64(v4, u64(in[24:32:len(in)]))
+
+ xx.memIdx = 0
+ }
+
+ for ; i < len(in)-31; i += 32 {
+ in := in[i : i+32 : len(in)]
+ v1 = round64(v1, u64(in[0:8:len(in)]))
+ v2 = round64(v2, u64(in[8:16:len(in)]))
+ v3 = round64(v3, u64(in[16:24:len(in)]))
+ v4 = round64(v4, u64(in[24:32:len(in)]))
+ }
+
+ if len(in)-i != 0 {
+ xx.memIdx += int8(copy(xx.mem[xx.memIdx:], in[i:len(in):len(in)]))
+ }
+
+ xx.v1, xx.v2, xx.v3, xx.v4 = v1, v2, v3, v4
+
+ return
+}
+
+func (xx *XXHash64) Sum64() (h uint64) {
+ var i int
+ if xx.ln > 31 {
+ v1, v2, v3, v4 := xx.v1, xx.v2, xx.v3, xx.v4
+ h = rotl64_1(v1) + rotl64_7(v2) + rotl64_12(v3) + rotl64_18(v4)
+
+ h = mergeRound64(h, v1)
+ h = mergeRound64(h, v2)
+ h = mergeRound64(h, v3)
+ h = mergeRound64(h, v4)
+ } else {
+ h = xx.seed + prime64x5
+ }
+
+ h += uint64(xx.ln)
+ if xx.memIdx > 0 {
+ in := xx.mem[:xx.memIdx]
+ for ; i < int(xx.memIdx)-7; i += 8 {
+ in := in[i : i+8 : len(in)]
+ k := u64(in[0:8:len(in)])
+ k *= prime64x2
+ k = rotl64_31(k)
+ k *= prime64x1
+ h ^= k
+ h = rotl64_27(h)*prime64x1 + prime64x4
+ }
+
+ for ; i < int(xx.memIdx)-3; i += 4 {
+ in := in[i : i+4 : len(in)]
+ h ^= uint64(u32(in[0:4:len(in)])) * prime64x1
+ h = rotl64_23(h)*prime64x2 + prime64x3
+ }
+
+ for ; i < int(xx.memIdx); i++ {
+ h ^= uint64(in[i]) * prime64x5
+ h = rotl64_11(h) * prime64x1
+ }
+ }
+
+ return mix64(h)
+}
diff --git a/vendor/github.com/OneOfOne/xxhash/xxhash_unsafe.go b/vendor/github.com/OneOfOne/xxhash/xxhash_unsafe.go
new file mode 100644
index 000000000..10f2e8429
--- /dev/null
+++ b/vendor/github.com/OneOfOne/xxhash/xxhash_unsafe.go
@@ -0,0 +1,239 @@
+// +build !safe
+// +build !appengine
+// +build !ppc64le
+// +build !mipsle
+// +build !ppc64be
+// +build !mips
+// +build !s390x
+
+package xxhash
+
+import (
+ "reflect"
+ "unsafe"
+)
+
+// Backend returns the current version of xxhash being used.
+const Backend = "GoUnsafe"
+
+// ChecksumString32S returns the checksum of the input data, without creating a copy, with the specific seed.
+func ChecksumString32S(s string, seed uint32) uint32 {
+ if len(s) == 0 {
+ return Checksum32S(nil, seed)
+ }
+ ss := (*reflect.StringHeader)(unsafe.Pointer(&s))
+ return Checksum32S((*[maxInt32]byte)(unsafe.Pointer(ss.Data))[:len(s):len(s)], seed)
+}
+
+func (xx *XXHash32) WriteString(s string) (int, error) {
+ if len(s) == 0 {
+ return 0, nil
+ }
+
+ ss := (*reflect.StringHeader)(unsafe.Pointer(&s))
+ return xx.Write((*[maxInt32]byte)(unsafe.Pointer(ss.Data))[:len(s):len(s)])
+}
+
+// ChecksumString64S returns the checksum of the input data, without creating a copy, with the specific seed.
+func ChecksumString64S(s string, seed uint64) uint64 {
+ if len(s) == 0 {
+ return Checksum64S(nil, seed)
+ }
+
+ ss := (*reflect.StringHeader)(unsafe.Pointer(&s))
+ return Checksum64S((*[maxInt32]byte)(unsafe.Pointer(ss.Data))[:len(s):len(s)], seed)
+}
+
+func (xx *XXHash64) WriteString(s string) (int, error) {
+ if len(s) == 0 {
+ return 0, nil
+ }
+ ss := (*reflect.StringHeader)(unsafe.Pointer(&s))
+ return xx.Write((*[maxInt32]byte)(unsafe.Pointer(ss.Data))[:len(s)])
+}
+
+func checksum64(in []byte, seed uint64) uint64 {
+ var (
+ wordsLen = len(in) >> 3
+ words = ((*[maxInt32 / 8]uint64)(unsafe.Pointer(&in[0])))[:wordsLen:wordsLen]
+
+ h uint64 = prime64x5
+
+ v1, v2, v3, v4 = resetVs64(seed)
+
+ i int
+ )
+
+ for ; i < len(words)-3; i += 4 {
+ words := (*[4]uint64)(unsafe.Pointer(&words[i]))
+
+ v1 = round64(v1, words[0])
+ v2 = round64(v2, words[1])
+ v3 = round64(v3, words[2])
+ v4 = round64(v4, words[3])
+ }
+
+ h = rotl64_1(v1) + rotl64_7(v2) + rotl64_12(v3) + rotl64_18(v4)
+
+ h = mergeRound64(h, v1)
+ h = mergeRound64(h, v2)
+ h = mergeRound64(h, v3)
+ h = mergeRound64(h, v4)
+
+ h += uint64(len(in))
+
+ for _, k := range words[i:] {
+ h ^= round64(0, k)
+ h = rotl64_27(h)*prime64x1 + prime64x4
+ }
+
+ if in = in[wordsLen<<3 : len(in) : len(in)]; len(in) > 3 {
+ words := (*[1]uint32)(unsafe.Pointer(&in[0]))
+ h ^= uint64(words[0]) * prime64x1
+ h = rotl64_23(h)*prime64x2 + prime64x3
+
+ in = in[4:len(in):len(in)]
+ }
+
+ for _, b := range in {
+ h ^= uint64(b) * prime64x5
+ h = rotl64_11(h) * prime64x1
+ }
+
+ return mix64(h)
+}
+
+func checksum64Short(in []byte, seed uint64) uint64 {
+ var (
+ h = seed + prime64x5 + uint64(len(in))
+ i int
+ )
+
+ if len(in) > 7 {
+ var (
+ wordsLen = len(in) >> 3
+ words = ((*[maxInt32 / 8]uint64)(unsafe.Pointer(&in[0])))[:wordsLen:wordsLen]
+ )
+
+ for i := range words {
+ h ^= round64(0, words[i])
+ h = rotl64_27(h)*prime64x1 + prime64x4
+ }
+
+ i = wordsLen << 3
+ }
+
+ if in = in[i:len(in):len(in)]; len(in) > 3 {
+ words := (*[1]uint32)(unsafe.Pointer(&in[0]))
+ h ^= uint64(words[0]) * prime64x1
+ h = rotl64_23(h)*prime64x2 + prime64x3
+
+ in = in[4:len(in):len(in)]
+ }
+
+ for _, b := range in {
+ h ^= uint64(b) * prime64x5
+ h = rotl64_11(h) * prime64x1
+ }
+
+ return mix64(h)
+}
+
+func (xx *XXHash64) Write(in []byte) (n int, err error) {
+ mem, idx := xx.mem[:], int(xx.memIdx)
+
+ xx.ln, n = xx.ln+uint64(len(in)), len(in)
+
+ if idx+len(in) < 32 {
+ xx.memIdx += int8(copy(mem[idx:len(mem):len(mem)], in))
+ return
+ }
+
+ var (
+ v1, v2, v3, v4 = xx.v1, xx.v2, xx.v3, xx.v4
+
+ i int
+ )
+
+ if d := 32 - int(idx); d > 0 && int(idx)+len(in) > 31 {
+ copy(mem[idx:len(mem):len(mem)], in[:len(in):len(in)])
+
+ words := (*[4]uint64)(unsafe.Pointer(&mem[0]))
+
+ v1 = round64(v1, words[0])
+ v2 = round64(v2, words[1])
+ v3 = round64(v3, words[2])
+ v4 = round64(v4, words[3])
+
+ if in, xx.memIdx = in[d:len(in):len(in)], 0; len(in) == 0 {
+ goto RET
+ }
+ }
+
+ for ; i < len(in)-31; i += 32 {
+ words := (*[4]uint64)(unsafe.Pointer(&in[i]))
+
+ v1 = round64(v1, words[0])
+ v2 = round64(v2, words[1])
+ v3 = round64(v3, words[2])
+ v4 = round64(v4, words[3])
+ }
+
+ if len(in)-i != 0 {
+ xx.memIdx += int8(copy(mem[xx.memIdx:len(mem):len(mem)], in[i:len(in):len(in)]))
+ }
+
+RET:
+ xx.v1, xx.v2, xx.v3, xx.v4 = v1, v2, v3, v4
+
+ return
+}
+
+func (xx *XXHash64) Sum64() (h uint64) {
+ if seed := xx.seed; xx.ln > 31 {
+ v1, v2, v3, v4 := xx.v1, xx.v2, xx.v3, xx.v4
+ h = rotl64_1(v1) + rotl64_7(v2) + rotl64_12(v3) + rotl64_18(v4)
+
+ h = mergeRound64(h, v1)
+ h = mergeRound64(h, v2)
+ h = mergeRound64(h, v3)
+ h = mergeRound64(h, v4)
+ } else if seed == 0 {
+ h = prime64x5
+ } else {
+ h = seed + prime64x5
+ }
+
+ h += uint64(xx.ln)
+
+ if xx.memIdx == 0 {
+ return mix64(h)
+ }
+
+ var (
+ in = xx.mem[:xx.memIdx:xx.memIdx]
+ wordsLen = len(in) >> 3
+ words = ((*[maxInt32 / 8]uint64)(unsafe.Pointer(&in[0])))[:wordsLen:wordsLen]
+ )
+
+ for _, k := range words {
+ h ^= round64(0, k)
+ h = rotl64_27(h)*prime64x1 + prime64x4
+ }
+
+ if in = in[wordsLen<<3 : len(in) : len(in)]; len(in) > 3 {
+ words := (*[1]uint32)(unsafe.Pointer(&in[0]))
+
+ h ^= uint64(words[0]) * prime64x1
+ h = rotl64_23(h)*prime64x2 + prime64x3
+
+ in = in[4:len(in):len(in)]
+ }
+
+ for _, b := range in {
+ h ^= uint64(b) * prime64x5
+ h = rotl64_11(h) * prime64x1
+ }
+
+ return mix64(h)
+}
diff --git a/vendor/github.com/gabriel-vasile/mimetype/CODE_OF_CONDUCT.md b/vendor/github.com/gabriel-vasile/mimetype/CODE_OF_CONDUCT.md
new file mode 100644
index 000000000..8479cd87d
--- /dev/null
+++ b/vendor/github.com/gabriel-vasile/mimetype/CODE_OF_CONDUCT.md
@@ -0,0 +1,76 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as
+contributors and maintainers pledge to making participation in our project and
+our community a harassment-free experience for everyone, regardless of age, body
+size, disability, ethnicity, sex characteristics, gender identity and expression,
+level of experience, education, socio-economic status, nationality, personal
+appearance, race, religion, or sexual identity and orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment
+include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or
+ advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic
+ address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable
+behavior and are expected to take appropriate and fair corrective action in
+response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or
+reject comments, commits, code, wiki edits, issues, and other contributions
+that are not aligned to this Code of Conduct, or to ban temporarily or
+permanently any contributor for other behaviors that they deem inappropriate,
+threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community. Examples of
+representing a project or community include using an official project e-mail
+address, posting via an official social media account, or acting as an appointed
+representative at an online or offline event. Representation of a project may be
+further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported by contacting the project team at vasile.gabriel@email.com. All
+complaints will be reviewed and investigated and will result in a response that
+is deemed necessary and appropriate to the circumstances. The project team is
+obligated to maintain confidentiality with regard to the reporter of an incident.
+Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good
+faith may face temporary or permanent repercussions as determined by other
+members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
+available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
+
+[homepage]: https://www.contributor-covenant.org
+
+For answers to common questions about this code of conduct, see
+https://www.contributor-covenant.org/faq
diff --git a/vendor/github.com/gabriel-vasile/mimetype/CONTRIBUTING.md b/vendor/github.com/gabriel-vasile/mimetype/CONTRIBUTING.md
new file mode 100644
index 000000000..56ae4e57c
--- /dev/null
+++ b/vendor/github.com/gabriel-vasile/mimetype/CONTRIBUTING.md
@@ -0,0 +1,12 @@
+## Contribute
+Contributions to **mimetype** are welcome. If you find an issue and you consider
+contributing, you can use the [Github issues tracker](https://github.com/gabriel-vasile/mimetype/issues)
+in order to report it, or better yet, open a pull request.
+
+Code contributions must respect these rules:
+ - code must be test covered
+ - code must be formatted using gofmt tool
+ - exported names must be documented
+
+**Important**: By submitting a pull request, you agree to allow the project
+owner to license your work under the same license as that used by the project.
diff --git a/vendor/github.com/gabriel-vasile/mimetype/LICENSE b/vendor/github.com/gabriel-vasile/mimetype/LICENSE
new file mode 100644
index 000000000..f1b456e91
--- /dev/null
+++ b/vendor/github.com/gabriel-vasile/mimetype/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018, 2019 Gabriel Vasile
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/github.com/gabriel-vasile/mimetype/README.md b/vendor/github.com/gabriel-vasile/mimetype/README.md
new file mode 100644
index 000000000..3d7f4afc5
--- /dev/null
+++ b/vendor/github.com/gabriel-vasile/mimetype/README.md
@@ -0,0 +1,64 @@
+
+ mimetype
+
+
+
+ A package for detecting MIME types and extensions based on magic numbers
+
+
+## Install
+```bash
+go get github.com/gabriel-vasile/mimetype
+```
+
+## Use
+The library exposes three functions you can use in order to detect a file type.
+See [Godoc](https://godoc.org/github.com/gabriel-vasile/mimetype) for full reference.
+```go
+func Detect(in []byte) (mime, extension string) {...}
+func DetectReader(r io.Reader) (mime, extension string, err error) {...}
+func DetectFile(file string) (mime, extension string, err error) {...}
+```
+When detecting from a `ReadSeeker` interface, such as `os.File`, make sure
+to reset the offset of the reader to the beginning if needed:
+```go
+_, err = file.Seek(0, io.SeekStart)
+```
+
+## Supported MIME types
+See [supported mimes](supported_mimes.md) for the list of detected MIME types.
+If support is needed for a specific file format, please open an [issue](https://github.com/gabriel-vasile/mimetype/issues/new/choose).
+
+## Structure
+**mimetype** uses an hierarchical structure to keep the matching functions.
+This reduces the number of calls needed for detecting the file type. The reason
+behind this choice is that there are file formats used as containers for other
+file formats. For example, Microsoft office files are just zip archives,
+containing specific metadata files.
+
+
+
+
+## Contributing
+See [CONTRIBUTING.md](CONTRIBUTING.md).
diff --git a/vendor/github.com/gabriel-vasile/mimetype/go.mod b/vendor/github.com/gabriel-vasile/mimetype/go.mod
new file mode 100644
index 000000000..6f8542d53
--- /dev/null
+++ b/vendor/github.com/gabriel-vasile/mimetype/go.mod
@@ -0,0 +1 @@
+module github.com/gabriel-vasile/mimetype
diff --git a/vendor/github.com/gabriel-vasile/mimetype/internal/json/json.go b/vendor/github.com/gabriel-vasile/mimetype/internal/json/json.go
new file mode 100644
index 000000000..9aef6cb4c
--- /dev/null
+++ b/vendor/github.com/gabriel-vasile/mimetype/internal/json/json.go
@@ -0,0 +1,536 @@
+// Copyright (c) 2009 The Go Authors. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// JSON value parser state machine.
+// This package is almost entirely copied from the Go stdlib.
+// Changes made to it permit users of the package to tell
+// if some slice of bytes is a valid beginning of a json string.
+package json
+
+import "fmt"
+
+type (
+ context int
+ scanStatus int
+)
+
+const (
+ contextKey context = iota
+ contextObj
+ contextArr
+
+ scanContinue scanStatus = iota // uninteresting byte
+ scanBeginLiteral // end implied by next result != scanContinue
+ scanBeginObject // begin object
+ scanObjectKey // just finished object key (string)
+ scanObjectValue // just finished non-last object value
+ scanEndObject // end object (implies scanObjectValue if possible)
+ scanBeginArray // begin array
+ scanArrayValue // just finished array value
+ scanEndArray // end array (implies scanArrayValue if possible)
+ scanSkipSpace // space byte; can skip; known to be last "continue" result
+ scanEnd // top-level value ended *before* this byte; known to be first "stop" result
+ scanError // hit an error, scanner.err.
+)
+
+type (
+ scanner struct {
+ step func(*scanner, byte) scanStatus
+ contexts []context
+ endTop bool
+ err error
+ index int
+ }
+)
+
+// Scan returns the number of bytes scanned and if there was any error
+// in trying to reach the end of data
+func Scan(data []byte) (int, error) {
+ s := &scanner{}
+ _ = checkValid(data, s)
+ return s.index, s.err
+}
+
+// checkValid verifies that data is valid JSON-encoded data.
+// scan is passed in for use by checkValid to avoid an allocation.
+func checkValid(data []byte, scan *scanner) error {
+ scan.reset()
+ for _, c := range data {
+ scan.index++
+ if scan.step(scan, c) == scanError {
+ return scan.err
+ }
+ }
+ if scan.eof() == scanError {
+ return scan.err
+ }
+ return nil
+}
+
+func isSpace(c byte) bool {
+ return c == ' ' || c == '\t' || c == '\r' || c == '\n'
+}
+
+func (s *scanner) reset() {
+ s.step = stateBeginValue
+ s.contexts = s.contexts[0:0]
+ s.err = nil
+}
+
+// eof tells the scanner that the end of input has been reached.
+// It returns a scan status just as s.step does.
+func (s *scanner) eof() scanStatus {
+ if s.err != nil {
+ return scanError
+ }
+ if s.endTop {
+ return scanEnd
+ }
+ s.step(s, ' ')
+ if s.endTop {
+ return scanEnd
+ }
+ if s.err == nil {
+ s.err = fmt.Errorf("unexpected end of JSON input")
+ }
+ return scanError
+}
+
+// pushContext pushes a new parse state p onto the parse stack.
+func (s *scanner) pushParseState(p context) {
+ s.contexts = append(s.contexts, p)
+}
+
+// popParseState pops a parse state (already obtained) off the stack
+// and updates s.step accordingly.
+func (s *scanner) popParseState() {
+ n := len(s.contexts) - 1
+ s.contexts = s.contexts[0:n]
+ if n == 0 {
+ s.step = stateEndTop
+ s.endTop = true
+ } else {
+ s.step = stateEndValue
+ }
+}
+
+// stateBeginValueOrEmpty is the state after reading `[`.
+func stateBeginValueOrEmpty(s *scanner, c byte) scanStatus {
+ if c <= ' ' && isSpace(c) {
+ return scanSkipSpace
+ }
+ if c == ']' {
+ return stateEndValue(s, c)
+ }
+ return stateBeginValue(s, c)
+}
+
+// stateBeginValue is the state at the beginning of the input.
+func stateBeginValue(s *scanner, c byte) scanStatus {
+ if c <= ' ' && isSpace(c) {
+ return scanSkipSpace
+ }
+ switch c {
+ case '{':
+ s.step = stateBeginStringOrEmpty
+ s.pushParseState(contextKey)
+ return scanBeginObject
+ case '[':
+ s.step = stateBeginValueOrEmpty
+ s.pushParseState(contextArr)
+ return scanBeginArray
+ case '"':
+ s.step = stateInString
+ return scanBeginLiteral
+ case '-':
+ s.step = stateNeg
+ return scanBeginLiteral
+ case '0': // beginning of 0.123
+ s.step = state0
+ return scanBeginLiteral
+ case 't': // beginning of true
+ s.step = stateT
+ return scanBeginLiteral
+ case 'f': // beginning of false
+ s.step = stateF
+ return scanBeginLiteral
+ case 'n': // beginning of null
+ s.step = stateN
+ return scanBeginLiteral
+ }
+ if '1' <= c && c <= '9' { // beginning of 1234.5
+ s.step = state1
+ return scanBeginLiteral
+ }
+ return s.error(c, "looking for beginning of value")
+}
+
+// stateBeginStringOrEmpty is the state after reading `{`.
+func stateBeginStringOrEmpty(s *scanner, c byte) scanStatus {
+ if c <= ' ' && isSpace(c) {
+ return scanSkipSpace
+ }
+ if c == '}' {
+ n := len(s.contexts)
+ s.contexts[n-1] = contextObj
+ return stateEndValue(s, c)
+ }
+ return stateBeginString(s, c)
+}
+
+// stateBeginString is the state after reading `{"key": value,`.
+func stateBeginString(s *scanner, c byte) scanStatus {
+ if c <= ' ' && isSpace(c) {
+ return scanSkipSpace
+ }
+ if c == '"' {
+ s.step = stateInString
+ return scanBeginLiteral
+ }
+ return s.error(c, "looking for beginning of object key string")
+}
+
+// stateEndValue is the state after completing a value,
+// such as after reading `{}` or `true` or `["x"`.
+func stateEndValue(s *scanner, c byte) scanStatus {
+ n := len(s.contexts)
+ if n == 0 {
+ // Completed top-level before the current byte.
+ s.step = stateEndTop
+ s.endTop = true
+ return stateEndTop(s, c)
+ }
+ if c <= ' ' && isSpace(c) {
+ s.step = stateEndValue
+ return scanSkipSpace
+ }
+ ps := s.contexts[n-1]
+ switch ps {
+ case contextKey:
+ if c == ':' {
+ s.contexts[n-1] = contextObj
+ s.step = stateBeginValue
+ return scanObjectKey
+ }
+ return s.error(c, "after object key")
+ case contextObj:
+ if c == ',' {
+ s.contexts[n-1] = contextKey
+ s.step = stateBeginString
+ return scanObjectValue
+ }
+ if c == '}' {
+ s.popParseState()
+ return scanEndObject
+ }
+ return s.error(c, "after object key:value pair")
+ case contextArr:
+ if c == ',' {
+ s.step = stateBeginValue
+ return scanArrayValue
+ }
+ if c == ']' {
+ s.popParseState()
+ return scanEndArray
+ }
+ return s.error(c, "after array element")
+ }
+ return s.error(c, "")
+}
+
+// stateEndTop is the state after finishing the top-level value,
+// such as after reading `{}` or `[1,2,3]`.
+// Only space characters should be seen now.
+func stateEndTop(s *scanner, c byte) scanStatus {
+ if c != ' ' && c != '\t' && c != '\r' && c != '\n' {
+ // Complain about non-space byte on next call.
+ s.error(c, "after top-level value")
+ }
+ return scanEnd
+}
+
+// stateInString is the state after reading `"`.
+func stateInString(s *scanner, c byte) scanStatus {
+ if c == '"' {
+ s.step = stateEndValue
+ return scanContinue
+ }
+ if c == '\\' {
+ s.step = stateInStringEsc
+ return scanContinue
+ }
+ if c < 0x20 {
+ return s.error(c, "in string literal")
+ }
+ return scanContinue
+}
+
+// stateInStringEsc is the state after reading `"\` during a quoted string.
+func stateInStringEsc(s *scanner, c byte) scanStatus {
+ switch c {
+ case 'b', 'f', 'n', 'r', 't', '\\', '/', '"':
+ s.step = stateInString
+ return scanContinue
+ case 'u':
+ s.step = stateInStringEscU
+ return scanContinue
+ }
+ return s.error(c, "in string escape code")
+}
+
+// stateInStringEscU is the state after reading `"\u` during a quoted string.
+func stateInStringEscU(s *scanner, c byte) scanStatus {
+ if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' {
+ s.step = stateInStringEscU1
+ return scanContinue
+ }
+ // numbers
+ return s.error(c, "in \\u hexadecimal character escape")
+}
+
+// stateInStringEscU1 is the state after reading `"\u1` during a quoted string.
+func stateInStringEscU1(s *scanner, c byte) scanStatus {
+ if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' {
+ s.step = stateInStringEscU12
+ return scanContinue
+ }
+ // numbers
+ return s.error(c, "in \\u hexadecimal character escape")
+}
+
+// stateInStringEscU12 is the state after reading `"\u12` during a quoted string.
+func stateInStringEscU12(s *scanner, c byte) scanStatus {
+ if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' {
+ s.step = stateInStringEscU123
+ return scanContinue
+ }
+ // numbers
+ return s.error(c, "in \\u hexadecimal character escape")
+}
+
+// stateInStringEscU123 is the state after reading `"\u123` during a quoted string.
+func stateInStringEscU123(s *scanner, c byte) scanStatus {
+ if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' {
+ s.step = stateInString
+ return scanContinue
+ }
+ // numbers
+ return s.error(c, "in \\u hexadecimal character escape")
+}
+
+// stateNeg is the state after reading `-` during a number.
+func stateNeg(s *scanner, c byte) scanStatus {
+ if c == '0' {
+ s.step = state0
+ return scanContinue
+ }
+ if '1' <= c && c <= '9' {
+ s.step = state1
+ return scanContinue
+ }
+ return s.error(c, "in numeric literal")
+}
+
+// state1 is the state after reading a non-zero integer during a number,
+// such as after reading `1` or `100` but not `0`.
+func state1(s *scanner, c byte) scanStatus {
+ if '0' <= c && c <= '9' {
+ s.step = state1
+ return scanContinue
+ }
+ return state0(s, c)
+}
+
+// state0 is the state after reading `0` during a number.
+func state0(s *scanner, c byte) scanStatus {
+ if c == '.' {
+ s.step = stateDot
+ return scanContinue
+ }
+ if c == 'e' || c == 'E' {
+ s.step = stateE
+ return scanContinue
+ }
+ return stateEndValue(s, c)
+}
+
+// stateDot is the state after reading the integer and decimal point in a number,
+// such as after reading `1.`.
+func stateDot(s *scanner, c byte) scanStatus {
+ if '0' <= c && c <= '9' {
+ s.step = stateDot0
+ return scanContinue
+ }
+ return s.error(c, "after decimal point in numeric literal")
+}
+
+// stateDot0 is the state after reading the integer, decimal point, and subsequent
+// digits of a number, such as after reading `3.14`.
+func stateDot0(s *scanner, c byte) scanStatus {
+ if '0' <= c && c <= '9' {
+ return scanContinue
+ }
+ if c == 'e' || c == 'E' {
+ s.step = stateE
+ return scanContinue
+ }
+ return stateEndValue(s, c)
+}
+
+// stateE is the state after reading the mantissa and e in a number,
+// such as after reading `314e` or `0.314e`.
+func stateE(s *scanner, c byte) scanStatus {
+ if c == '+' || c == '-' {
+ s.step = stateESign
+ return scanContinue
+ }
+ return stateESign(s, c)
+}
+
+// stateESign is the state after reading the mantissa, e, and sign in a number,
+// such as after reading `314e-` or `0.314e+`.
+func stateESign(s *scanner, c byte) scanStatus {
+ if '0' <= c && c <= '9' {
+ s.step = stateE0
+ return scanContinue
+ }
+ return s.error(c, "in exponent of numeric literal")
+}
+
+// stateE0 is the state after reading the mantissa, e, optional sign,
+// and at least one digit of the exponent in a number,
+// such as after reading `314e-2` or `0.314e+1` or `3.14e0`.
+func stateE0(s *scanner, c byte) scanStatus {
+ if '0' <= c && c <= '9' {
+ return scanContinue
+ }
+ return stateEndValue(s, c)
+}
+
+// stateT is the state after reading `t`.
+func stateT(s *scanner, c byte) scanStatus {
+ if c == 'r' {
+ s.step = stateTr
+ return scanContinue
+ }
+ return s.error(c, "in literal true (expecting 'r')")
+}
+
+// stateTr is the state after reading `tr`.
+func stateTr(s *scanner, c byte) scanStatus {
+ if c == 'u' {
+ s.step = stateTru
+ return scanContinue
+ }
+ return s.error(c, "in literal true (expecting 'u')")
+}
+
+// stateTru is the state after reading `tru`.
+func stateTru(s *scanner, c byte) scanStatus {
+ if c == 'e' {
+ s.step = stateEndValue
+ return scanContinue
+ }
+ return s.error(c, "in literal true (expecting 'e')")
+}
+
+// stateF is the state after reading `f`.
+func stateF(s *scanner, c byte) scanStatus {
+ if c == 'a' {
+ s.step = stateFa
+ return scanContinue
+ }
+ return s.error(c, "in literal false (expecting 'a')")
+}
+
+// stateFa is the state after reading `fa`.
+func stateFa(s *scanner, c byte) scanStatus {
+ if c == 'l' {
+ s.step = stateFal
+ return scanContinue
+ }
+ return s.error(c, "in literal false (expecting 'l')")
+}
+
+// stateFal is the state after reading `fal`.
+func stateFal(s *scanner, c byte) scanStatus {
+ if c == 's' {
+ s.step = stateFals
+ return scanContinue
+ }
+ return s.error(c, "in literal false (expecting 's')")
+}
+
+// stateFals is the state after reading `fals`.
+func stateFals(s *scanner, c byte) scanStatus {
+ if c == 'e' {
+ s.step = stateEndValue
+ return scanContinue
+ }
+ return s.error(c, "in literal false (expecting 'e')")
+}
+
+// stateN is the state after reading `n`.
+func stateN(s *scanner, c byte) scanStatus {
+ if c == 'u' {
+ s.step = stateNu
+ return scanContinue
+ }
+ return s.error(c, "in literal null (expecting 'u')")
+}
+
+// stateNu is the state after reading `nu`.
+func stateNu(s *scanner, c byte) scanStatus {
+ if c == 'l' {
+ s.step = stateNul
+ return scanContinue
+ }
+ return s.error(c, "in literal null (expecting 'l')")
+}
+
+// stateNul is the state after reading `nul`.
+func stateNul(s *scanner, c byte) scanStatus {
+ if c == 'l' {
+ s.step = stateEndValue
+ return scanContinue
+ }
+ return s.error(c, "in literal null (expecting 'l')")
+}
+
+// stateError is the state after reaching a syntax error,
+// such as after reading `[1}` or `5.1.2`.
+func stateError(s *scanner, c byte) scanStatus {
+ return scanError
+}
+
+// error records an error and switches to the error state.
+func (s *scanner) error(c byte, context string) scanStatus {
+ s.step = stateError
+ s.err = fmt.Errorf("invalid character <<%c>> %s", c, context)
+ return scanError
+}
diff --git a/vendor/github.com/gabriel-vasile/mimetype/internal/json/json_test.go b/vendor/github.com/gabriel-vasile/mimetype/internal/json/json_test.go
new file mode 100644
index 000000000..1e9c659fb
--- /dev/null
+++ b/vendor/github.com/gabriel-vasile/mimetype/internal/json/json_test.go
@@ -0,0 +1,39 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package json
+
+import "testing"
+
+var scanTests = []struct {
+ data string
+ length int
+ ok bool
+}{
+ {`foo`, 2, false},
+ {`}{`, 1, false},
+ {`{]`, 2, false},
+ {`{}`, 2, true},
+ {`{"foo":"bar"}`, 13, true},
+ {`{"foo":"bar","bar":{"baz":["qux"]}`, 34, false},
+ {`{"foo":"bar","bar":{"baz":["qux"]}}`, 35, true},
+}
+
+func TestScan(t *testing.T) {
+ for _, st := range scanTests {
+ scanned, err := Scan([]byte(st.data))
+ if scanned != st.length {
+ t.Errorf("Scan length error: expected: %d; got: %d; input: %s",
+ st.length, scanned, st.data)
+ }
+
+ if err != nil && st.ok {
+ t.Errorf("Scan failed with err: %s; input: %s", err, st.data)
+ }
+
+ if err == nil && !st.ok {
+ t.Errorf("Scan should fail for input: %s", st.data)
+ }
+ }
+}
diff --git a/vendor/github.com/gabriel-vasile/mimetype/internal/matchers/archive.go b/vendor/github.com/gabriel-vasile/mimetype/internal/matchers/archive.go
new file mode 100644
index 000000000..6dfd59df0
--- /dev/null
+++ b/vendor/github.com/gabriel-vasile/mimetype/internal/matchers/archive.go
@@ -0,0 +1,70 @@
+package matchers
+
+import "bytes"
+
+// Zip matches a zip archive.
+func Zip(in []byte) bool {
+ return len(in) > 3 &&
+ in[0] == 0x50 && in[1] == 0x4B &&
+ (in[2] == 0x3 || in[2] == 0x5 || in[2] == 0x7) &&
+ (in[3] == 0x4 || in[3] == 0x6 || in[3] == 0x8)
+}
+
+// SevenZ matches a 7z archive.
+func SevenZ(in []byte) bool {
+ return len(in) > 6 &&
+ bytes.Equal(in[:6], []byte{0x37, 0x7A, 0xBC, 0xAF, 0x27, 0x1C})
+}
+
+// Epub matches an EPUB file.
+func Epub(in []byte) bool {
+ return len(in) > 58 && bytes.Equal(in[30:58], []byte("mimetypeapplication/epub+zip"))
+}
+
+// Jar matches a Java archive file.
+func Jar(in []byte) bool {
+ return bytes.Contains(in, []byte("META-INF/MANIFEST.MF"))
+}
+
+// Gzip matched gzip files based on http://www.zlib.org/rfc-gzip.html#header-trailer.
+func Gzip(in []byte) bool {
+ return len(in) > 2 && bytes.Equal(in[:2], []byte{0x1f, 0x8b})
+}
+
+// Crx matches a Chrome extension file: a zip archive prepended by "Cr24".
+func Crx(in []byte) bool {
+ return len(in) > 4 && bytes.Equal(in[:4], []byte("Cr24"))
+}
+
+// Tar matches a (t)ape (ar)chive file.
+func Tar(in []byte) bool {
+ return len(in) > 262 && bytes.Equal(in[257:262], []byte("ustar"))
+}
+
+// Fits matches an Flexible Image Transport System file.
+func Fits(in []byte) bool {
+ return bytes.HasPrefix(in, []byte{0x53, 0x49, 0x4D, 0x50, 0x4C, 0x45, 0x20,
+ 0x20, 0x3D, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x54})
+}
+
+// Xar matches an eXtensible ARchive format file.
+func Xar(in []byte) bool {
+ return bytes.HasPrefix(in, []byte{0x78, 0x61, 0x72, 0x21})
+}
+
+// Bz2 matches a bzip2 file.
+func Bz2(in []byte) bool {
+ return bytes.HasPrefix(in, []byte{0x42, 0x5A, 0x68})
+}
+
+// Ar matches an ar (Unix) archive file.
+func Ar(in []byte) bool {
+ return bytes.HasPrefix(in, []byte{0x21, 0x3C, 0x61, 0x72, 0x63, 0x68, 0x3E})
+}
+
+// Deb matches a Debian package file
+func Deb(in []byte) bool {
+ return len(in) > 8 && bytes.HasPrefix(in[8:], []byte{0x64, 0x65, 0x62, 0x69,
+ 0x61, 0x6E, 0x2D, 0x62, 0x69, 0x6E, 0x61, 0x72, 0x79})
+}
diff --git a/vendor/github.com/gabriel-vasile/mimetype/internal/matchers/audio.go b/vendor/github.com/gabriel-vasile/mimetype/internal/matchers/audio.go
new file mode 100644
index 000000000..32f7440a5
--- /dev/null
+++ b/vendor/github.com/gabriel-vasile/mimetype/internal/matchers/audio.go
@@ -0,0 +1,59 @@
+package matchers
+
+import (
+ "bytes"
+)
+
+// Mp3 matches an mp3 file.
+func Mp3(in []byte) bool {
+ return bytes.HasPrefix(in, []byte("\x49\x44\x33"))
+}
+
+// Flac matches a Free Lossless Audio Codec file.
+func Flac(in []byte) bool {
+ return bytes.HasPrefix(in, []byte("\x66\x4C\x61\x43\x00\x00\x00\x22"))
+}
+
+// Midi matches a Musical Instrument Digital Interface file.
+func Midi(in []byte) bool {
+ return bytes.HasPrefix(in, []byte("\x4D\x54\x68\x64"))
+}
+
+// Ape matches a Monkey's Audio file.
+func Ape(in []byte) bool {
+ return bytes.HasPrefix(in, []byte("\x4D\x41\x43\x20\x96\x0F\x00\x00\x34\x00\x00\x00\x18\x00\x00\x00\x90\xE3"))
+}
+
+// MusePack matches a Musepack file.
+func MusePack(in []byte) bool {
+ return len(in) > 4 && bytes.Equal(in[:4], []byte("MPCK"))
+}
+
+// Wav matches a Waveform Audio File Format file.
+func Wav(in []byte) bool {
+ return len(in) > 12 &&
+ bytes.Equal(in[:4], []byte("\x52\x49\x46\x46")) &&
+ bytes.Equal(in[8:12], []byte("\x57\x41\x56\x45"))
+}
+
+// Aiff matches Audio Interchange File Format file.
+func Aiff(in []byte) bool {
+ return len(in) > 12 &&
+ bytes.Equal(in[:4], []byte("\x46\x4F\x52\x4D")) &&
+ bytes.Equal(in[8:12], []byte("\x41\x49\x46\x46"))
+}
+
+// Ogg matches an Ogg file.
+func Ogg(in []byte) bool {
+ return len(in) > 5 && bytes.Equal(in[:5], []byte("\x4F\x67\x67\x53\x00"))
+}
+
+// Au matches a Sun Microsystems au file.
+func Au(in []byte) bool {
+ return len(in) > 4 && bytes.Equal(in[:4], []byte("\x2E\x73\x6E\x64"))
+}
+
+// Amr matches an Adaptive Multi-Rate file.
+func Amr(in []byte) bool {
+ return len(in) > 5 && bytes.Equal(in[:5], []byte("\x23\x21\x41\x4D\x52"))
+}
diff --git a/vendor/github.com/gabriel-vasile/mimetype/internal/matchers/binary.go b/vendor/github.com/gabriel-vasile/mimetype/internal/matchers/binary.go
new file mode 100644
index 000000000..eb864b18a
--- /dev/null
+++ b/vendor/github.com/gabriel-vasile/mimetype/internal/matchers/binary.go
@@ -0,0 +1,85 @@
+package matchers
+
+import (
+ "bytes"
+)
+
+// Class matches an java class file.
+func Class(in []byte) bool {
+ return len(in) > 4 && bytes.Equal(in[:4], []byte{0xCA, 0xFE, 0xBA, 0xBE})
+}
+
+// Swf matches an Adobe Flash swf file.
+func Swf(in []byte) bool {
+ return len(in) > 3 &&
+ bytes.Equal(in[:3], []byte("CWS")) ||
+ bytes.Equal(in[:3], []byte("FWS")) ||
+ bytes.Equal(in[:3], []byte("ZWS"))
+}
+
+// Wasm matches a web assembly File Format file.
+func Wasm(in []byte) bool {
+ return len(in) > 4 && bytes.Equal(in[:4], []byte{0x00, 0x61, 0x73, 0x6D})
+}
+
+// Dbf matches a dBase file.
+// https://www.dbase.com/Knowledgebase/INT/db7_file_fmt.htm
+func Dbf(in []byte) bool {
+ // 3rd and 4th bytes contain the last update month and day of month
+ if !(0 < in[2] && in[2] < 13 && 0 < in[3] && in[3] < 32) {
+ return false
+ }
+
+ // dbf type is dictated by the first byte
+ dbfTypes := []byte{
+ 0x02, 0x03, 0x04, 0x05, 0x30, 0x31, 0x32, 0x42, 0x62, 0x7B, 0x82,
+ 0x83, 0x87, 0x8A, 0x8B, 0x8E, 0xB3, 0xCB, 0xE5, 0xF5, 0xF4, 0xFB,
+ }
+ for _, b := range dbfTypes {
+ if in[0] == b {
+ return true
+ }
+ }
+
+ return false
+}
+
+// Exe matches a Windows/DOS executable file.
+func Exe(in []byte) bool {
+ return bytes.HasPrefix(in, []byte{0x4D, 0x5A})
+}
+
+// Elf matches an Executable and Linkable Format file.
+func Elf(in []byte) bool {
+ return bytes.HasPrefix(in, []byte{0x7F, 0x45, 0x4C, 0x46})
+}
+
+// ElfObj matches an object file.
+func ElfObj(in []byte) bool {
+ return len(in) > 17 && ((in[16] == 0x01 && in[17] == 0x00) ||
+ (in[16] == 0x00 && in[17] == 0x01))
+}
+
+// ElfExe matches an executable file.
+func ElfExe(in []byte) bool {
+ return len(in) > 17 && ((in[16] == 0x02 && in[17] == 0x00) ||
+ (in[16] == 0x00 && in[17] == 0x02))
+}
+
+// ElfLib matches a shared library file.
+func ElfLib(in []byte) bool {
+ return len(in) > 17 && ((in[16] == 0x03 && in[17] == 0x00) ||
+ (in[16] == 0x00 && in[17] == 0x03))
+}
+
+// ElfDump matches a core dump file.
+func ElfDump(in []byte) bool {
+ return len(in) > 17 && ((in[16] == 0x04 && in[17] == 0x00) ||
+ (in[16] == 0x00 && in[17] == 0x04))
+}
+
+// Dcm matches a DICOM medical format file.
+func Dcm(in []byte) bool {
+ return len(in) > 131 &&
+ bytes.Equal(in[128:132], []byte{0x44, 0x49, 0x43, 0x4D})
+}
diff --git a/vendor/github.com/gabriel-vasile/mimetype/internal/matchers/document.go b/vendor/github.com/gabriel-vasile/mimetype/internal/matchers/document.go
new file mode 100644
index 000000000..cfa82671c
--- /dev/null
+++ b/vendor/github.com/gabriel-vasile/mimetype/internal/matchers/document.go
@@ -0,0 +1,8 @@
+package matchers
+
+import "bytes"
+
+// Pdf matches a Portable Document Format file.
+func Pdf(in []byte) bool {
+ return len(in) > 4 && bytes.Equal(in[:4], []byte{0x25, 0x50, 0x44, 0x46})
+}
diff --git a/vendor/github.com/gabriel-vasile/mimetype/internal/matchers/fonts.go b/vendor/github.com/gabriel-vasile/mimetype/internal/matchers/fonts.go
new file mode 100644
index 000000000..d5f62a793
--- /dev/null
+++ b/vendor/github.com/gabriel-vasile/mimetype/internal/matchers/fonts.go
@@ -0,0 +1,13 @@
+package matchers
+
+import "bytes"
+
+// Woff matches a Web Open Font Format file.
+func Woff(in []byte) bool {
+ return len(in) > 4 && bytes.Equal(in[:4], []byte("wOFF"))
+}
+
+// Woff2 matches a Web Open Font Format version 2 file.
+func Woff2(in []byte) bool {
+ return len(in) > 4 && bytes.Equal(in[:4], []byte("wOF2"))
+}
diff --git a/vendor/github.com/gabriel-vasile/mimetype/internal/matchers/geo.go b/vendor/github.com/gabriel-vasile/mimetype/internal/matchers/geo.go
new file mode 100644
index 000000000..4c82b5301
--- /dev/null
+++ b/vendor/github.com/gabriel-vasile/mimetype/internal/matchers/geo.go
@@ -0,0 +1,44 @@
+package matchers
+
+import (
+ "bytes"
+ "encoding/binary"
+)
+
+// Shp matches a shape format file.
+// https://www.esri.com/library/whitepapers/pdfs/shapefile.pdf
+func Shp(in []byte) bool {
+ if len(in) < 112 {
+ return false
+ }
+ shapeTypes := []int{
+ 0, // Null shape
+ 1, // Point
+ 3, // Polyline
+ 5, // Polygon
+ 8, // MultiPoint
+ 11, // PointZ
+ 13, // PolylineZ
+ 15, // PolygonZ
+ 18, // MultiPointZ
+ 21, // PointM
+ 23, // PolylineM
+ 25, // PolygonM
+ 28, // MultiPointM
+ 31, // MultiPatch
+ }
+
+ for _, st := range shapeTypes {
+ if st == int(binary.LittleEndian.Uint32(in[108:112])) {
+ return true
+ }
+ }
+
+ return false
+}
+
+// Shx matches a shape index format file.
+// https://www.esri.com/library/whitepapers/pdfs/shapefile.pdf
+func Shx(in []byte) bool {
+ return len(in) > 4 && bytes.Equal(in[:4], []byte{0x00, 0x00, 0x27, 0x0A})
+}
diff --git a/vendor/github.com/gabriel-vasile/mimetype/internal/matchers/image.go b/vendor/github.com/gabriel-vasile/mimetype/internal/matchers/image.go
new file mode 100644
index 000000000..df9c0c31d
--- /dev/null
+++ b/vendor/github.com/gabriel-vasile/mimetype/internal/matchers/image.go
@@ -0,0 +1,56 @@
+package matchers
+
+import "bytes"
+
+// Png matches a Portable Network Graphics file.
+func Png(in []byte) bool {
+ return len(in) > 8 &&
+ bytes.Equal(in[:8], []byte{0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A})
+}
+
+// Jpg matches a Joint Photographic Experts Group file.
+func Jpg(in []byte) bool {
+ return len(in) > 3 && bytes.Equal(in[:3], []byte{0xFF, 0xD8, 0xFF})
+}
+
+// Gif matches a Graphics Interchange Format file.
+func Gif(in []byte) bool {
+ return bytes.HasPrefix(in, []byte("GIF87a")) ||
+ bytes.HasPrefix(in, []byte("GIF89a"))
+}
+
+// Webp matches a WebP file.
+func Webp(in []byte) bool {
+ return len(in) > 12 &&
+ bytes.Equal(in[0:4], []byte{0x52, 0x49, 0x46, 0x46}) &&
+ bytes.Equal(in[8:12], []byte{0x57, 0x45, 0x42, 0x50})
+}
+
+// Bmp matches a bitmap image file.
+func Bmp(in []byte) bool {
+ return len(in) > 1 && in[0] == 0x42 && in[1] == 0x4D
+}
+
+// Ps matches a PostScript file.
+func Ps(in []byte) bool {
+ return bytes.HasPrefix(in, []byte("%!PS-Adobe-"))
+}
+
+// Psd matches a Photoshop Document file.
+func Psd(in []byte) bool {
+ return bytes.HasPrefix(in, []byte("8BPS"))
+}
+
+// Ico matches an ICO file.
+func Ico(in []byte) bool {
+ return len(in) > 3 &&
+ in[0] == 0x00 && in[1] == 0x00 &&
+ in[2] == 0x01 && in[3] == 0x00
+}
+
+// Tiff matches a Tagged Image File Format file.
+func Tiff(in []byte) bool {
+ return len(in) > 4 &&
+ (bytes.Equal(in[:4], []byte{0x49, 0x49, 0x2A, 0x00}) ||
+ bytes.Equal(in[:4], []byte{0x4D, 0x4D, 0x00, 0x2A}))
+}
diff --git a/vendor/github.com/gabriel-vasile/mimetype/internal/matchers/matchers.go b/vendor/github.com/gabriel-vasile/mimetype/internal/matchers/matchers.go
new file mode 100644
index 000000000..6170443a8
--- /dev/null
+++ b/vendor/github.com/gabriel-vasile/mimetype/internal/matchers/matchers.go
@@ -0,0 +1,46 @@
+// Package matchers holds the matching functions used to find mime types.
+package matchers
+
+// ReadLimit is the maximum number of bytes read
+// from the input when detecting a reader.
+const ReadLimit = 2048
+
+// True is a dummy matching function used to match any input.
+func True([]byte) bool {
+ return true
+}
+
+// False is a dummy matching function used to never match input.
+func False([]byte) bool {
+ return false
+}
+
+// trimLWS trims whitespace from beginning of the input.
+func trimLWS(in []byte) []byte {
+ firstNonWS := 0
+ for ; firstNonWS < len(in) && isWS(in[firstNonWS]); firstNonWS++ {
+ }
+
+ return in[firstNonWS:]
+}
+
+// trimRWS trims whitespace from the end of the input.
+func trimRWS(in []byte) []byte {
+ lastNonWS := len(in) - 1
+ for ; lastNonWS > 0 && isWS(in[lastNonWS]); lastNonWS-- {
+ }
+
+ return in[:lastNonWS+1]
+}
+
+func firstLine(in []byte) []byte {
+ lineEnd := 0
+ for ; lineEnd < len(in) && in[lineEnd] != '\n'; lineEnd++ {
+ }
+
+ return in[:lineEnd]
+}
+
+func isWS(b byte) bool {
+ return b == '\t' || b == '\n' || b == '\x0c' || b == '\r' || b == ' '
+}
diff --git a/vendor/github.com/gabriel-vasile/mimetype/internal/matchers/ms_office.go b/vendor/github.com/gabriel-vasile/mimetype/internal/matchers/ms_office.go
new file mode 100644
index 000000000..7c0ce1d85
--- /dev/null
+++ b/vendor/github.com/gabriel-vasile/mimetype/internal/matchers/ms_office.go
@@ -0,0 +1,80 @@
+package matchers
+
+import (
+ "bytes"
+ "fmt"
+ "strings"
+)
+
+// Xlsx matches a Microsoft Excel 2007 file.
+func Xlsx(in []byte) bool {
+ return bytes.Contains(in, []byte("xl/"))
+}
+
+// Docx matches a Microsoft Office 2007 file.
+func Docx(in []byte) bool {
+ return bytes.Contains(in, []byte("word/"))
+}
+
+// Pptx matches a Microsoft PowerPoint 2007 file.
+func Pptx(in []byte) bool {
+ return bytes.Contains(in, []byte("ppt/"))
+}
+
+// Doc matches a Microsoft Office 97-2003 file.
+func Doc(in []byte) bool {
+ if len(in) < 516 {
+ return false
+ }
+
+ head := fmt.Sprintf("%X", in[:8])
+ offset512 := fmt.Sprintf("%X", in[512:516])
+
+ return head == "D0CF11E0A1B11AE1" && offset512 == "ECA5C100"
+}
+
+// Ppt matches a Microsoft PowerPoint 97-2003 file.
+func Ppt(in []byte) bool {
+ if len(in) < 520 {
+ return false
+ }
+
+ if fmt.Sprintf("%X", in[:8]) == "D0CF11E0A1B11AE1" {
+ offset512 := fmt.Sprintf("%X", in[512:516])
+ if offset512 == "A0461DF0" || offset512 == "006E1EF0" || offset512 == "0F00E803" {
+ return true
+ }
+ if offset512 == "FDFFFFFF" && fmt.Sprintf("%x", in[518:520]) == "0000" {
+ return true
+ }
+ }
+
+ return false
+}
+
+// Xls matches a Microsoft Excel 97-2003 file.
+func Xls(in []byte) bool {
+ if len(in) < 520 {
+ return false
+ }
+
+ if fmt.Sprintf("%X", in[:8]) == "D0CF11E0A1B11AE1" {
+ offset512 := fmt.Sprintf("%X", in[512:520])
+ subheaders := []string{
+ "0908100000060500",
+ "FDFFFFFF10",
+ "FDFFFFFF1F",
+ "FDFFFFFF22",
+ "FDFFFFFF23",
+ "FDFFFFFF28",
+ "FDFFFFFF29",
+ }
+ for _, h := range subheaders {
+ if strings.HasPrefix(offset512, h) {
+ return true
+ }
+ }
+ }
+
+ return false
+}
diff --git a/vendor/github.com/gabriel-vasile/mimetype/internal/matchers/odf.go b/vendor/github.com/gabriel-vasile/mimetype/internal/matchers/odf.go
new file mode 100644
index 000000000..ad31e666b
--- /dev/null
+++ b/vendor/github.com/gabriel-vasile/mimetype/internal/matchers/odf.go
@@ -0,0 +1,48 @@
+package matchers
+
+import "bytes"
+
+// Odt matches an OpenDocument Text file.
+func Odt(in []byte) bool {
+ return bytes.Contains(in, []byte("mimetypeapplication/vnd.oasis.opendocument.text"))
+}
+
+// Ott matches an OpenDocument Text Template file.
+func Ott(in []byte) bool {
+ return bytes.Contains(in, []byte("mimetypeapplication/vnd.oasis.opendocument.text-template"))
+}
+
+// Ods matches an OpenDocument Spreadsheet file.
+func Ods(in []byte) bool {
+ return bytes.Contains(in, []byte("mimetypeapplication/vnd.oasis.opendocument.spreadsheet"))
+}
+
+// Ots matches an OpenDocument Spreadsheet Template file.
+func Ots(in []byte) bool {
+ return bytes.Contains(in, []byte("mimetypeapplication/vnd.oasis.opendocument.spreadsheet-template"))
+}
+
+// Odp matches an OpenDocument Presentation file.
+func Odp(in []byte) bool {
+ return bytes.Contains(in, []byte("mimetypeapplication/vnd.oasis.opendocument.presentation"))
+}
+
+// Otp matches an OpenDocument Presentation Template file.
+func Otp(in []byte) bool {
+ return bytes.Contains(in, []byte("mimetypeapplication/vnd.oasis.opendocument.presentation-template"))
+}
+
+// Odg matches an OpenDocument Drawing file.
+func Odg(in []byte) bool {
+ return bytes.Contains(in, []byte("mimetypeapplication/vnd.oasis.opendocument.graphics"))
+}
+
+// Otg matches an OpenDocument Drawing Template file.
+func Otg(in []byte) bool {
+ return bytes.Contains(in, []byte("mimetypeapplication/vnd.oasis.opendocument.graphics-template"))
+}
+
+// Odf matches an OpenDocument Formula file.
+func Odf(in []byte) bool {
+ return bytes.Contains(in, []byte("mimetypeapplication/vnd.oasis.opendocument.formula"))
+}
diff --git a/vendor/github.com/gabriel-vasile/mimetype/internal/matchers/signature.go b/vendor/github.com/gabriel-vasile/mimetype/internal/matchers/signature.go
new file mode 100644
index 000000000..a3364de40
--- /dev/null
+++ b/vendor/github.com/gabriel-vasile/mimetype/internal/matchers/signature.go
@@ -0,0 +1,125 @@
+package matchers
+
+import (
+ "bytes"
+ "fmt"
+)
+
+type (
+ markupSig []byte
+ ciSig []byte // case insensitive signature
+ shebangSig []byte // matches !# followed by the signature
+ ftypSig []byte // matches audio/video files. www.ftyps.com
+ xmlSig struct {
+ // the local name of the root tag
+ localName []byte
+ // the namespace of the XML document
+ xmlns []byte
+ }
+ sig interface {
+ detect([]byte) bool
+ }
+)
+
+func newXmlSig(localName, xmlns string) xmlSig {
+ ret := xmlSig{xmlns: []byte(xmlns)}
+ if localName != "" {
+ ret.localName = []byte(fmt.Sprintf("<%s", localName))
+ }
+
+ return ret
+}
+
+// Implement sig interface.
+func (hSig markupSig) detect(in []byte) bool {
+ if len(in) < len(hSig)+1 {
+ return false
+ }
+
+ // perform case insensitive check
+ for i, b := range hSig {
+ db := in[i]
+ if 'A' <= b && b <= 'Z' {
+ db &= 0xDF
+ }
+ if b != db {
+ return false
+ }
+ }
+ // Next byte must be space or right angle bracket.
+ if db := in[len(hSig)]; db != ' ' && db != '>' {
+ return false
+ }
+
+ return true
+}
+
+// Implement sig interface.
+func (tSig ciSig) detect(in []byte) bool {
+ if len(in) < len(tSig)+1 {
+ return false
+ }
+
+ // perform case insensitive check
+ for i, b := range tSig {
+ db := in[i]
+ if 'A' <= b && b <= 'Z' {
+ db &= 0xDF
+ }
+ if b != db {
+ return false
+ }
+ }
+
+ return true
+}
+
+// a valid shebang starts with the "#!" characters
+// followed by any number of spaces
+// followed by the path to the interpreter and optionally, the args for the interpreter
+func (sSig shebangSig) detect(in []byte) bool {
+ in = firstLine(in)
+
+ if len(in) < len(sSig)+2 {
+ return false
+ }
+ if in[0] != '#' || in[1] != '!' {
+ return false
+ }
+
+ in = trimLWS(trimRWS(in[2:]))
+
+ return bytes.Equal(in, sSig)
+}
+
+// Implement sig interface.
+func (fSig ftypSig) detect(in []byte) bool {
+ return len(in) > 12 &&
+ bytes.Equal(in[4:8], []byte("ftyp")) &&
+ bytes.Equal(in[8:12], fSig)
+}
+
+func (xSig xmlSig) detect(in []byte) bool {
+ l := 512
+ if len(in) < l {
+ l = len(in)
+ }
+ in = in[:l]
+
+ if len(xSig.localName) == 0 {
+ return bytes.Index(in, xSig.xmlns) > 0
+ }
+
+ localNameIndex := bytes.Index(in, xSig.localName)
+ return localNameIndex != -1 && localNameIndex < bytes.Index(in, xSig.xmlns)
+}
+
+func detect(in []byte, sigs []sig) bool {
+ for _, sig := range sigs {
+ if sig.detect(in) {
+ return true
+ }
+ }
+
+ return false
+}
diff --git a/vendor/github.com/gabriel-vasile/mimetype/internal/matchers/text.go b/vendor/github.com/gabriel-vasile/mimetype/internal/matchers/text.go
new file mode 100644
index 000000000..9af1b9132
--- /dev/null
+++ b/vendor/github.com/gabriel-vasile/mimetype/internal/matchers/text.go
@@ -0,0 +1,255 @@
+package matchers
+
+import (
+ "bytes"
+
+ "github.com/gabriel-vasile/mimetype/internal/json"
+)
+
+var (
+ htmlSigs = []sig{
+ markupSig(" 6 && bytes.Equal(in[:6], []byte("{\\rtf1"))
+}
+
+// Svg matches a SVG file.
+func Svg(in []byte) bool {
+ return bytes.Contains(in, []byte("